Common Errors
EServiceAlreadyRegistered
Symptom: Exception raised at startup or at a call to Singleton<T>, SingletonLazy<T>, SingletonInterface<I,T>, Factory<T>, or AddInject.
Message: Class <T> registered! or Interface <T> already registered! or Injector <tag> already registered!
Cause: The same class, interface GUID, or tag was registered more than once. This commonly happens when:
- A unit's
initializationblock is executed multiple times (e.g., loaded from two different BPL packages that both include the unit). - You have a conditional branch that registers a service on multiple code paths.
Fix:
- Guard registrations with
if not FRepositoryReference.ContainsKey(T.ClassName) then ...in ambiguous paths. - Use
AddInstance<T>when you control the construction and want to overwrite an existing registration (but note this also raises if already registered — useRemove<T>first if needed).
EServiceNotFound
Symptom: Exception raised at GetInterface<I>.
Message: Interface <GUID-string> not found!
Cause: GetInterface<I> was called before the interface was registered, or the interface I does not have a GUID, or the correct unit was not in the uses clause causing initialization to never run.
Fix:
- Ensure the unit that contains
GetInjector.SingletonInterface<I, T>is in theusesclause of either the.dpror a unit transitively referenced at startup. - Confirm the interface
Ihas a GUID attribute (['{...}']). - Use
GetInjector.GetInstancesto inspect what is actually registered.
ECircularDependency
Symptom: Exception during Get<T> or GetInterface<I>.
Message: Circular dependency detected: TServiceA -> TServiceB -> TServiceA
Cause: Two (or more) services depend on each other, forming a cycle. The dependency stack detects this when the same service name appears twice on the stack.
Fix: See Circular Dependency Detection — How to fix.
Get<T> returns nil unexpectedly
Symptom: GetInjector.Get<T> returns nil but no exception is raised.
Cause: Get<T> returns nil (not raises) when the service is not found. Either:
- The service was not registered.
- The registration unit's
initializationblock did not execute (unit not referenced inuses). - The tag passed does not match the registration tag.
Fix:
- Add a nil check and log:
if not Assigned(LSvc) then raise Exception.Create('TMyService not registered'). - Confirm the registration unit is in the
usesclause. - Enable logging (
EnableLogging) and watch forGet Service:lines.
RTTI: class has no parameterless Create constructor
Symptom: Access violation or RTTI exception during auto-wired lazy resolution.
Cause: _ResolverParams calls TRttiType.GetMethod('Create') and attempts to invoke it with auto-resolved parameters. If the class has no Create method visible to RTTI (e.g., inherited from TInterfacedObject with no public override), the method may not be found.
Fix: Declare an explicit constructor Create; in the class so RTTI can locate and invoke it. Alternatively, supply AOnConstructorParams to bypass auto-wiring:
GetInjector.SingletonLazy<TMyClass>(
nil, nil,
function: TConstructorParams
begin
Result := []; // no params
end
);
Package-lock.json mismatch (documentation build only)
Symptom: npm ci fails in the CI workflow with npm error Invalid: lock file's <package> errors.
Cause: package.json was updated but package-lock.json was not regenerated.
Fix: Run npm install locally inside docs-src/ and commit the updated package-lock.json.
Logging shows [Injector4D] prefix instead of [InjectContainer]
Symptom: Log messages contain [Injector4D] in the prefix.
Cause: The _Log method in Inject.pas uses a hardcoded prefix '[Injector4D]'. This is the internal code name; the public framework name is InjectContainer.
Fix: This is cosmetic only and does not affect functionality. The prefix [Injector4D] is hardcoded in TInject._Log (Inject.pas) and has not been changed to [InjectContainer] in the current source.