Skip to content
Buy me a coffee

Errors

Every error the container throws extends IocError, which extends Error. Each has its own class, so you can tell them apart with instanceof, and its own name, so logs show which one it was. Messages name the tokens involved and, where it applies, the path of services being resolved.

Error Thrown when Extra fields Thrown by
ServiceNotFoundError A required service, or a dependency of one, has no registration token, key, path getRequired*, resolving dependencies
CircularDependencyError A cycle partner was used before its constructor finished path Resolution
ScopeError Scoped service resolved from the root, or captured by a singleton (validateScopes) none Resolution
RegistrationError A registration is invalid: too few dependency tokens, a non-class token with no implementation none add*, tryAdd*, replace
ValidationError validateOnBuild found problems errors: string[] buildServiceProvider
DisposedError A provider or scope was used after dispose() none get*, createScope

Errors thrown by your own code (a constructor, a factory, onInit, onDestroy) pass through unchanged.

interface
interface Mailer
Mailer
{
Mailer.send(to: string): Promise<void>
send
(
to: string
to
: string):
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<void>;
}
const
const Mailer: InjectionToken<Mailer>
Mailer
=
createToken<Mailer>(name: string): InjectionToken<Mailer>

Creates a typed token.

@example

interface Logger { log(msg: string): void }
const Logger = createToken<Logger>('Logger');
services.addSingleton(Logger, ConsoleLogger);
const logger = await provider.getRequiredService(Logger); // typed as Logger

createToken
<
interface Mailer
Mailer
>('Mailer');
class
class SignupService
SignupService
{
constructor(readonly
SignupService.mailer: Mailer
mailer
:
interface Mailer
Mailer
) {}
}
const
const provider: ServiceProvider
provider
= new
new ServiceCollection(): ServiceCollection

Collects service registrations, then builds a

ServiceProvider

. Modeled on .NET's IServiceCollection.

@example

const services = new ServiceCollection();
services.addSingleton(Logger, ConsoleLogger);
services.addScoped(UserService, [Logger]);
const provider = services.buildServiceProvider({ validateScopes: true });

ServiceCollection
().
ServiceCollection.addTransient<SignupService, [mailer: Mailer]>(token: Newable<SignupService, [mailer: Mailer]>, dependencies: readonly [mailer: Token<Mailer>]): ServiceCollection (+4 overloads)

Registers a transient service: a new instance on every resolution. Same forms as

addSingleton

.

addTransient
(
class SignupService
SignupService
, [
const Mailer: InjectionToken<Mailer>
Mailer
]).
ServiceCollection.buildServiceProvider(options?: BuildOptions): ServiceProvider

Builds the provider. Registrations are copied, so changing this collection afterwards does not affect providers already built.

buildServiceProvider
();
try {
await
const provider: ServiceProvider
provider
.
ServiceProvider.getRequiredService<SignupService>(token: Token<SignupService>): Promise<SignupService>

Resolves token, throwing ServiceNotFoundError if it is not registered.

getRequiredService
(
class SignupService
SignupService
);
} catch (
var error: unknown
error
) {
if (
var error: unknown
error
instanceof
class ServiceNotFoundError

A required service (or one of its dependencies) has no registration.

ServiceNotFoundError
) {
var error: ServiceNotFoundError
error
.
Error.message: string
message
; // "No service registered for 'Mailer' (required by SignupService)."
function tokenName(token: Token | undefined): string

Readable name of a token, for messages and diagnostics.

tokenName
(
var error: ServiceNotFoundError
error
.
ServiceNotFoundError.token: Token
token
); // 'Mailer'
var error: ServiceNotFoundError
error
.
ServiceNotFoundError.path: readonly Token[]

Services that were being resolved when the missing one was needed, outermost first.

path
.
ReadonlyArray<Token>.map<string>(callbackfn: (value: Token, index: number, array: readonly Token[]) => string, thisArg?: any): string[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

map
(
function tokenName(token: Token | undefined): string

Readable name of a token, for messages and diagnostics.

tokenName
); // ['SignupService']: what was being resolved, outermost first
}
}

For keyed lookups, key holds the key and the message says with key '…'. getService and getKeyedService return undefined for a missing top-level service instead of throwing, but a missing dependency of a registered service still throws.

Thrown when a constructor uses a cycle partner that isn’t constructed yet. path is the cycle, starting and ending with the service that was used too early: A → B → A.

Only with validateScopes: true. Two messages:

  • Scoped service 'X' cannot be resolved from the root provider. Create a scope first: …
  • Scoped service 'X' cannot be injected into singleton 'Y' (Y → … → X): the singleton would keep one scope's instance forever.

See Validation.

Thrown by the registration call itself, so a bad registration fails at startup, at the line that made it:

  • 'UserService' has 2 constructor parameter(s) but 1 dependency token(s) were given for 'UserService'. …
  • 'Logger' is not a class: register it with an implementation or a factory. (a string, symbol or InjectionToken registered without an implementation)

Thrown by buildServiceProvider({ validateOnBuild: true }). errors lists every problem; the message joins them as a bulleted list.

Cannot use a disposed service provider or scope. Thrown by every get* method and createScope() after the provider or scope was disposed, and on any scope after its root was disposed. A get* call that was still building its service when the owner was disposed rejects with it too (the half-built service is disposed). dispose() itself never throws it: later calls wait for the first disposal.

Catch IocError to separate container problems (wiring bugs, almost always) from errors your services throw:

try {
const
const reports: ReportService
reports
= await
const scope: ServiceProvider
scope
.
ServiceProvider.getRequiredService<ReportService>(token: Token<ReportService>): Promise<ReportService>

Resolves token, throwing ServiceNotFoundError if it is not registered.

getRequiredService
(
class ReportService
ReportService
);
await
const reports: ReportService
reports
.
ReportService.run(): Promise<void>
run
();
} catch (
var error: unknown
error
) {
if (
var error: unknown
error
instanceof
class IocError

Base class of every error thrown by the container.

IocError
) {
const log: {
error(msg: string, err: unknown): void;
}
log
.
function error(msg: string, err: unknown): void
error
('container misconfigured',
var error: IocError
error
); // a bug: alert, don't retry
}
throw
var error: unknown
error
;
}

Errors raised while disposing are your services’ own errors, rethrown after every instance was disposed (an AggregateError if more than one failed). See Lifecycle and disposal.