Skip to Content
ErrorsNEXUS_INTERCEPTORS_UNCHECKED

This page documents the 0.4 release candidates of @nexusdi/core. The newest on npm is 0.4.0-rc.1. The documentation for 0.3.2, the current release, is at nexus.js.org. Try the release candidate.

NEXUS_INTERCEPTORS_UNCHECKED

The construct hook of an interceptors() plugin throws NEXUS_INTERCEPTORS_UNCHECKED when it receives a provider that no compile.check of that plugin recorded. The plugin decides each service’s interceptors while it checks the graph, so it refuses to wrap an instance it has no record of. A container that calls the plugin’s hooks in order never raises it. It appears when a plugin that decorates another plugin’s compile.check without forwarding the view keeps the check from seeing the graph, by dropping the hook or by handing it copies of the provider views, or when code outside the container calls construct by hand.

How the error arrives depends on the caller of the hook. When the container calls construct, Nexus.create rejects with NEXUS_PROVIDER_FAILED. Its cause is a NEXUS_PLUGIN_FAILED whose hook is 'construct', and that error’s cause is this error. When code outside the container calls construct, the call throws this error.

@nexusdi/interceptors raises this error inside a hook, where no container formats it, so the message carries its full text with a text pack or without one. When several providers fail the same way, the provider error reports one of them and lists the others in alsoFailed. In the region below, alsoFailed lists Audit, the interceptor’s provider, and interceptors guard, the plugin’s own guard.

Reproduce NEXUS_INTERCEPTORS_UNCHECKED

The region wraps the plugin in an object that keeps its modules and construct hook and replaces its compile hook with an empty one, so no check of the plugin sees a provider. Nexus.create then builds ReactorCore through construct and rejects.

import { Nexus, Token, defineModule, provide } from '@nexusdi/core'; import { isNexusError } from '@nexusdi/core'; import type { NexusPlugin } from '@nexusdi/core'; import { interceptor, interceptors } from '@nexusdi/interceptors'; import type { CallContext, Interceptor, Next } from '@nexusdi/interceptors'; interface IReactorCore { output(): number; } const REACTOR = new Token<IReactorCore>('ReactorCore'); const AUDIT = new Token<Interceptor>('Audit'); class AuditInterceptor implements Interceptor { intercept(_call: CallContext, next: Next) { return next(); } } class FusionReactor implements IReactorCore { output() { return 1.21; } } const Engineering = defineModule({ name: 'Engineering', providers: [provide(REACTOR, { useClass: FusionReactor })], exports: [REACTOR], }); const real = interceptors({ register: [interceptor(AUDIT, { useClass: AuditInterceptor })], global: [AUDIT], }); // A wrapper that forwards the plugin's modules and construct hook, and drops // its compile hook, so no compile.check of the plugin sees any provider. const wrapped: NexusPlugin = { ...real, compile: {} }; const error = await Nexus.create(Engineering, { plugins: [wrapped] }).catch( (caught: unknown) => caught, ); if (!isNexusError(error, 'NEXUS_PROVIDER_FAILED')) throw error; const pluginError = error.cause; if (!isNexusError(pluginError, 'NEXUS_PLUGIN_FAILED')) throw error; const inner = pluginError.cause; // the code of an error, or null const codeOf = (e: unknown) => (isNexusError(e) ? e.code : null); const codes = [error, pluginError, inner].map(codeOf); // -> ['NEXUS_PROVIDER_FAILED', 'NEXUS_PLUGIN_FAILED', 'NEXUS_INTERCEPTORS_UNCHECKED'] console.log(codes); const hook = pluginError.hook; // -> 'construct' console.log(hook); const also = error.alsoFailed.map((other) => other.token); // -> ['Audit', 'interceptors guard'] console.log(also); const lines = isNexusError(inner) ? inner.message.split('\n') : null; // -> ['[NEXUS_INTERCEPTORS_UNCHECKED] ReactorCore was built from a provider that no compile.check of this interceptors() plugin saw, so its interceptors are unknown.', " Fix: install @nexusdi/interceptors at the version of @nexusdi/core, and let only the container call the plugin's hooks."] console.log(lines);

Try it: run npm install @nexusdi/core@next @nexusdi/interceptors@next, save the region as unchecked.ts and run npx tsx unchecked.ts. It prints the chain of codes as an array, NEXUS_PROVIDER_FAILED, NEXUS_PLUGIN_FAILED, NEXUS_INTERCEPTORS_UNCHECKED, one to a line, then construct, then the tokens of alsoFailed, [ 'Audit', 'interceptors guard' ], then the message as an array of two lines: [NEXUS_INTERCEPTORS_UNCHECKED] ReactorCore was built from a provider that no compile.check of this interceptors() plugin saw, so its interceptors are unknown. and Fix: install @nexusdi/interceptors at the version of @nexusdi/core, and let only the container call the plugin's hooks. Then run the fix region.

Fix NEXUS_INTERCEPTORS_UNCHECKED

NEXUS_INTERCEPTORS_UNCHECKED goes away when the container alone calls the plugin’s hooks. Pass the plugin to Nexus.create as interceptors() returned it. The message’s own fix line adds that @nexusdi/interceptors should be installed at the version of @nexusdi/core, and npm ls @nexusdi/interceptors lists every copy.

import { Nexus, Token, defineModule, provide } from '@nexusdi/core'; import { interceptor, interceptors } from '@nexusdi/interceptors'; import type { CallContext, Interceptor, Next } from '@nexusdi/interceptors'; interface IReactorCore { output(): number; } const REACTOR = new Token<IReactorCore>('ReactorCore'); const AUDIT = new Token<Interceptor>('Audit'); class AuditInterceptor implements Interceptor { intercept(_call: CallContext, next: Next) { return next(); } } class FusionReactor implements IReactorCore { output() { return 1.21; } } const Engineering = defineModule({ name: 'Engineering', providers: [provide(REACTOR, { useClass: FusionReactor })], exports: [REACTOR], }); const real = interceptors({ register: [interceptor(AUDIT, { useClass: AuditInterceptor })], global: [AUDIT], }); // The container calls every hook of the plugin, and no other code does. await using ship = await Nexus.create(Engineering, { plugins: [real] }); const output = ship.get(REACTOR).output(); // -> 1.21 console.log(output);

The fix region differs from the reproduce region in the plugin list, which holds real itself, and in what follows: it keeps the container and prints the output of ReactorCore.

Try it: save the region as fixed.ts and run npx tsx fixed.ts. It prints 1.21. Change plugins: [real] to plugins: [{ ...real, compile: {} }] and run it again. npx tsc accepts the file, and npx tsx fixed.ts throws an uncaught ProviderError and prints a stack trace headed ProviderError: [NEXUS_PROVIDER_FAILED] token=ReactorCore module=Engineering path=ReactorCore. and the address of this page, which nests the PluginError and the InterceptorError: [NEXUS_INTERCEPTORS_UNCHECKED] message as its causes. Change it back and the program prints 1.21 again.

Method Interceptors covers the plugin’s options.

Fields of InterceptorError

  • code: 'NEXUS_INTERCEPTORS_UNCHECKED'.
  • reason: null for this code.
  • token: null for this code.
  • target: the name of the provider whose instance the hook received.
  • method: null for this code.
  • state: null for this code.
  • detail: an empty list for this code.