BabylonJS/Babylon.js · error

Decorator metadata is unavailable; the Symbol.metadata (${St

Error message

Decorator metadata is unavailable; the Symbol.metadata (${String(MetadataSymbol)}) polyfill must run before decorated classes are evaluated.

What it means

Decorator metadata (Symbol.metadata) was not installed before a decorated class was evaluated, so decorator context.metadata arrives as undefined. The library throws an explicit, actionable error instead of the cryptic 'Cannot convert undefined to object' that Object.keys/HasOwn would produce, and to keep the polyfill module anchored against tree-shaking.

Source

Thrown at packages/dev/core/src/Misc/decorators.functions.ts:93

            writable: true,
            enumerable: false,
        });
    }
    return ctor[MetadataSymbol];
}

/**
 * Returns (creating if necessary) the serialization store owned by the provided decorator metadata.
 * Used by the TC39 decorators, which receive `context.metadata` directly.
 * @internal
 */
export function GetDirectStoreFromMetadata(metadata: DecoratorMetadataObject): SerializedPropertyMetadataMap {
    if (!metadata) {
        // `metadata` is `context.metadata`, which is `void 0` when `Symbol.metadata` was not installed
        // before the class was evaluated. Referencing `MetadataSymbol` here (a) produces an actionable
        // error instead of a cryptic "Cannot convert undefined to object" and (b) keeps the module-load
        // polyfill anchored so bundlers cannot tree-shake it away on the decorate-time serialize path.
        throw new Error(`Decorator metadata is unavailable; the Symbol.metadata (${String(MetadataSymbol)}) polyfill must run before decorated classes are evaluated.`);
    }
    if (!HasOwn(metadata, __bjsSerializableKey)) {
        (metadata as any)[__bjsSerializableKey] = {};
    }
    return (metadata as any)[__bjsSerializableKey];
}

/** @internal */
export function GetDirectStore(target: any): SerializedPropertyMetadataMap {
    const metadata = GetOwnMetadata(GetConstructor(target));
    if (!metadata) {
        return {};
    }
    if (!HasOwn(metadata, __bjsSerializableKey)) {
        metadata[__bjsSerializableKey] = {};
    }
    return metadata[__bjsSerializableKey];
}

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Import the library's metadata polyfill entry at the very top of your app entry point (before any decorated class module is imported)
  2. Ensure the polyfill import is not tree-shaken: import it for side effects and mark it as such in bundler config (e.g. rollup sideEffects flag)
  3. Verify the runtime supports Symbol.metadata or that the polyfill runs on all targets; check bundle chunk ordering so the polyfill executes first

Example fix

// before
import { serializable } from 'core/Misc/decorators';
@serializable()
class Foo {}
// after
import 'core/Misc/decorators.metadata'; // polyfill, must run first
import { serializable } from 'core/Misc/decorators';
@serializable()
class Foo {}
Defensive patterns

Strategy: validation

Validate before calling

if (typeof (Symbol as any).metadata !== 'symbol') {
  throw new Error('Symbol.metadata unavailable: import the decorators metadata polyfill before decorated classes');
}

Try / catch

try {
  serialize(obj);
} catch (e) {
  if (e instanceof Error && e.message.includes('Decorator metadata is unavailable')) {
    console.error('Add `import "core/Misc/decorators.metadata"` as the first import in your entry point', e);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Serializing a class decorated with the library's serializable decorators when the Symbol.metadata polyfill did not run at module load — typically when the decorators module is imported lazily, or a bundler tree-shook the polyfill side effect, or targeting an environment without Symbol.metadata and no polyfill import.

Common situations: ESBuild/rollup tree-shaking away a side-effect-only polyfill import; importing only decorator functions without the polyfill entry point; upgrading the runtime (older Node/browsers lacking Symbol.metadata) without updating setup code; split bundles where the polyfill chunk loads after the decorated class chunk.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/3b3280209cd6bcff. Report an issue: GitHub.