Errors
Every message the packages throw, verbatim, grouped by error class. Registration errors fire where the provider is registered, not where it is later read; resolution errors fire at the read. X and Y stand for your token names.
The error classes
@remodulo/container throws four typed classes, all exported. Catch by instanceof, or by code - the code survives two copies of the package in one process, where instanceof does not:
| Class | code | Carries |
|---|---|---|
RegistrationError | REMODULO/REGISTRATION | token - when the failing provider names one |
ResolutionError | REMODULO/RESOLUTION | token, mode - the width of the failed read |
CycleError (extends ResolutionError) | REMODULO/CYCLE | chain - the ring as an array of tokens |
InjectionContextError | REMODULO/INJECTION_CONTEXT | caller - which injector was misused |
try {
container.resolve(OrdersApi)
} catch (error) {
if (error instanceof ResolutionError) report(error.code, error.token, error.mode)
}@remodulo/react throws plain Errors - and two AggregateErrors in teardown. No codes; match by message.
RegistrationError - REMODULO/REGISTRATION
Fires at register, where the provider is declared.
Token X is already registered on this container
Token X is already registered on this container. One token, one registration - mark every provider for it
multi: trueto make it a collection, or give each provider its own token.
When: a second single registration claimed an already-claimed token on the same container. Fix: as the message says - multi: true everywhere, or separate tokens.
Token X is already single / multi
Token X is already a single registration on this container, and this provider registers it as a multi-provider collection. A token is one or the other for the whole container chain - that is what lets
resolveandresolveAllagree about what it means. Dropmulti: truehere, or add it to the other registration.
When: a provider disagrees with the token's existing mode. "On an ancestor container" means the conflict crosses the chain; the fix sentence flips direction with the mismatch. Fix: make every provider for the token agree on multi.
Provider with multi: true requires provide
Provider with
multi: truerequiresprovide- the class shorthand registers under the class itself, and a collection whose only member is that class is just the class. Name the collection's token explicitly.
When: { useClass, multi: true } with no provide. Fix: give the collection an explicit token.
Provider with useValue / useFactory / useExisting requires provide
Provider with useFactory requires
provide- only useClass may register under its own token, because a class is one. Give this provider an explicit token.
When: an object form other than { useClass } has no provide. Fix: add the token.
X has no recognised form
X has no recognised form - expected a class, or an object with one of useClass, useValue, useFactory or useExisting.
When: register received something that is neither a class nor a valid provider object. Fix: check the value - a typo'd key, an accidental instance, an undefined import.
X mixes implementation keys
X mixes 2 implementation keys (useClass, useValue) - a provider declares exactly one of useClass, useValue, useFactory or useExisting. Note that an explicit
undefinedstill counts as declared.
When: a provider object carries more than one use* key - including one set to undefined. Fix: keep exactly one.
Provider for X cannot alias Y
Provider for X cannot alias Y: Y is a multi-provider collection, and
useExistingis a single-value read of its target - it redirects to exactly the readresolveperforms, andresolverefuses a collection. Alias a single registration, or contribute to the collection with{ provide: Y, ..., multi: true }.
When: useExisting targets a collection token - in either registration order. Fix: as the message says.
ResolutionError - REMODULO/RESOLUTION
Fires at the read.
Token X is not registered
Token X is not registered in this container or any ancestor.
When: resolve / inject found no declaration at this container or above. Fix: register the token here or in an ancestor, or read with resolveOptional / resolveOr if absence is legal.
Token X is not registered in this container (mode "self" reads its own bindings only). Use "nearest" to search its ancestors too.
When: the same miss under mode: "self" - an inherited registration is a miss by design. Fix: use "nearest", or declare the token on this container.
Token X is a multi-provider collection
Token X is a multi-provider collection - several providers contribute to it, so there is no single value to read. Use
resolveAll.
When: resolve / inject / entry on a collection token. Fix: resolveAll / injectAll / entries.
Token X is a single registration
Token X is a single registration, not a multi-provider collection -
resolveAllwould hide that behind a one-element array. Useresolve, or mark every provider for itmulti: true.
When: resolveAll / injectAll / entries on a single-registration token. Fix: resolve, or make the token a collection.
CycleError - REMODULO/CYCLE
Circular dependency found
Circular dependency found: A -> B -> A
When: two providers need each other at construction; the message is the ring, alias hops included, and the same ring is on error.chain. Fix: { delayed: true } on one side - Circular Dependencies.
InjectionContextError - REMODULO/INJECTION_CONTEXT
inject() was called outside a construction frame
inject(X) was called outside a construction frame.
injectreads the container that is building right now, so it only works synchronously inside a constructor body, a field initializer, or auseFactorybody. In an async factory that means BEFORE the firstawait- once the factory yields, the frame is gone. Outside construction, read from a container directly withresolve, or open a frame explicitly withrunInInjectionContext. A frame that should be there and is not can also mean two copies of @remodulo/container in one process: each holds its own frame, and injection never crosses between them.
When: an injector ran outside construction - a method, a callback, after an await. error.caller names the injector. Fix: move the read into construction, take injectResolver() at construction and read later, or use { delayed: true }. See Dependency Injection.
makeTokenizer
Plain errors, thrown at mint time.
makeTokenizer:
namespacemust be a non-empty string.
Token:
namemust be a non-empty string.
When: an empty or whitespace-only namespace or token name. Fix: pass real names; the namespace should be your package name.
@remodulo/react
Plain Errors - no codes, match by message.
ModuleProvider requires a parent module
ModuleProvider requires a parent module in context. Wrap it in
<AppProvider>, or nest it under another<ModuleProvider>.
When: a scoped module rendered outside <AppProvider> - including a createModuleComponent component. Fix: as the message says. See The Tree.
useModuleContext: no module in context
useModuleContext: no module in context. Wrap with
<AppProvider>or<ModuleProvider>.
When: useModuleContext / useModule / useResolver / useResolve outside any module boundary. Fix: move the component under a module, or wrap it in one.
AppProvider does not support replacing its App instance
AppProvider does not support replacing its App instance
When: the app prop changed identity between renders - typically a module-level const app in a file that hot reloads, or new App(...) inline in JSX. Fix: keep one instance for the life of the tree - export the const, or pass a factory: app={() => new App({ ... })}.
App failed to initialize.
App failed to initialize.
When: a provider threw during the App's init; the original error is logged right before this one. Fix: read the logged error - this one only reports the state.
App was destroyed. Provide a fresh App.
App was destroyed. Provide a fresh App.
When: an AppProvider received an App whose lifecycle already ended. Fix: construct a new App - a destroyed module is not revivable.
Cannot create a child module from an un-initialized parent
Cannot create a child module from an un-initialized parent - its lifecycle is not armed yet, so instances would leak. Init the parent first.
When: a module was constructed under a parent that has not run init() yet. Fix: init the parent first; under React this ordering is handled for you.
Cannot create a child module under a failed / destroyed parent
Cannot create a child module under a failed parent - that branch is spent, so the child could never be armed. Build it under a live parent, or rebuild the branch first.
When: constructing a module under a parent that is failed, destroying, or destroyed. Fix: rebuild the branch - Module Rebuild.
Cannot mount a module onto a failed / destroying / destroyed parent
Cannot mount a module onto a failed parent - that branch is spent, so the child could never go live under it. Mount it under a live parent, or rebuild the branch first.
When: the boundary mounted while its parent module was already dying. Fix: rebuild the branch, or fix whatever failed the parent - the log right above has it.
Cannot init() / mount() / unmount() / destroy() a module whose status is X
Cannot mount() a module whose status is "created" - mount() accepts "initialized" or "unmounted".
When: a lifecycle signal arrived in the wrong phase. Under React this indicates a bug above the module layer - the providers drive these calls in order. Fix: if you drive a module by hand, follow Lifecycle Phases.
Cannot resolve X from a module whose status is "..."
Cannot resolve X from a module whose status is "failed" - a module answers reads only once init() has armed it, and never after it failed or was destroyed.
When: a read through a module before init, or after it failed or was destroyed. Fix: for a failed module, the init error above it is the real problem; a destroyed module needs a rebuild.
Cannot resolve X from an unhealthy module tree
Cannot resolve X from an unhealthy module tree - failed branch: orders. Every module under a failed ancestor refuses reads, whichever module owns the binding.
When: a read anywhere below a failed or destroyed ancestor; the id in the message is the ancestor's. Fix: fix or rebuild the named branch.
Provider for X declares lazy: ... while the collection is lazy: ...
Provider for X declares
lazy: truewhile the collection already registered for that token islazy: false. A collection is constructed whole - oneresolveAllin the owner's eager pass - so a partly-lazy one has no coherent meaning. Make every useClass, useFactory, useValue and useExisting member agree.
When: a collection's members disagree on lazy. Fix: all eager or all lazy.
AggregateError: Errors occurred while unmounting module subtree
When: one or more onModuleUnmount hooks threw; every participant still ran, and the errors are collected on error.errors. Fix: each entry is a real bug in a hook - unmount itself completed.
AggregateError: Module mount failed and rollback encountered errors
When: onModuleMount threw AND the best-effort rollback hit further errors; the first entry is the original mount error, the rest are teardown fallout. Fix: the first entry is the cause.