emberjs/ember.js · error · Error
Custom component managers must have a `capabilities` propert
Error message
Custom component managers must have a `capabilities` property that is the result of calling the `capabilities('3.13')` (imported via `import { capabilities } from '@ember/component';`). Received: `${JSON.stringify(delegate.capabilities)}` for: `${delegate}` What it means
When a component definition is first used, `getDelegateFor` instantiates the custom component manager and verifies its `capabilities` property was produced by the real `capabilities('3.13')` function (tracked via an internal FROM_CAPABILITIES set). A manager whose capabilities object was hand-built, faked, or produced by a different copy of the library fails this check and throws, including a JSON dump of what was received.
Source
Thrown at packages/@glimmer/manager/lib/public/component.ts:129
O extends Owner,
ComponentInstance,
> implements InternalComponentManager<CustomComponentState<ComponentInstance>> {
private componentManagerDelegates = new WeakMap<O, ComponentManager<ComponentInstance>>();
constructor(private factory: ManagerFactory<O, ComponentManager<ComponentInstance>>) {}
private getDelegateFor(owner: O) {
let { componentManagerDelegates } = this;
let delegate = componentManagerDelegates.get(owner);
if (delegate === undefined) {
let { factory } = this;
delegate = factory(owner);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme
if (DEBUG && !FROM_CAPABILITIES!.has(delegate.capabilities)) {
// TODO: This error message should make sense in both Ember and Glimmer https://github.com/glimmerjs/glimmer-vm/issues/1200
throw new Error(
`Custom component managers must have a \`capabilities\` property that is the result of calling the \`capabilities('3.13')\` (imported via \`import { capabilities } from '@ember/component';\`). Received: \`${JSON.stringify(
delegate.capabilities
// eslint-disable-next-line @typescript-eslint/no-base-to-string
)}\` for: \`${delegate}\``
);
}
componentManagerDelegates.set(owner, delegate);
}
return delegate;
}
create(
owner: O,
definition: ComponentDefinitionState,
vmArgs: VMArguments
): CustomComponentState<ComponentInstance> {View on GitHub (pinned to 26f97246a8)
Solutions
- Set `static capabilities = capabilities('3.13')` on the manager class using the real import from @glimmer/manager (or Ember's @ember/component re-export)
- Never hand-construct a capabilities-shaped object literal
- Deduplicate @glimmer/manager so the manager and the capabilities producer share one module instance
- Inspect the JSON in the error to confirm whether capabilities is undefined (missing property) or a fake object
Example fix
// before
class MyManager {
capabilities = { asyncLifeCycleCallbacks: true, createInstance: true };
}
// after
import { capabilities } from '@ember/component'; // or @glimmer/manager
class MyManager {
capabilities = capabilities('3.13', { asyncLifeCycleCallbacks: true, createInstance: true });
} Defensive patterns
Strategy: validation
Validate before calling
import { capabilities } from '@ember/component';
class MyManager {
static create(attrs) { return new this(attrs); }
capabilities = capabilities('3.13', { asyncLifecycleCallbacks: true, createInstance: true, updateHook: true });
}
// verify before use:
console.assert(typeof MyManager.prototype.capabilities === 'object'); Type guard
function hasRealCapabilities(m: unknown): m is { capabilities: ComponentCapabilities } { return m !== null && typeof m === 'object' && m.capabilities instanceof Object && Object.isFrozen(m.capabilities); } Try / catch
try { owner.factoryFor('component:x').create(); } catch (e) { if (/must have a `capabilities` property/.test(e.message)) { console.error('Manager capabilities not built by capabilities(); check for duplicate @glimmer/manager copies'); } throw e; } Prevention
- Only assign capabilities from the real capabilities() function, never object literals
- Deduplicate @glimmer/manager across dependencies
- Render each custom component in a smoke test
When it happens
Trigger: A component manager class whose `capabilities` is a plain object literal `{ asyncLifeCycleCallbacks: true, ... }` instead of the result of `capabilities('3.13')`; or `capabilities` imported from a duplicate/mismatched copy of @glimmer/manager so the token check fails.
Common situations: Mocking capabilities in tests with plain objects; duplicated @glimmer/manager versions in node_modules; managers written against old Glimmer versions before capabilities tokens existed.
Related errors
- Invalid component manager compatibility specified
- You attempted to mount the engine '${name}', but it is not r
- Attempted to load a helper, but there wasn't a helper manage
- Invalid helper manager compatibility specified; you specifie
- You must pass either the `hasValue` OR the `hasScheduledEffe
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/5475648146ad84db.
Report an issue: GitHub.