BabylonJS/Babylon.js · error

SmartAssetManager: Key "${key}" is not registered. Provide a

Error message

SmartAssetManager: Key "${key}" is not registered. Provide a URL to auto-register.

What it means

LoadSmartAssetAsync was called with a key that has no URL registered in the SmartAssetManager's internal registry, and no url argument was supplied to auto-register it. The manager only serves assets whose key->URL mapping was previously added via RegisterSmartAsset (or a prior load with a url). Without a resolved URL it cannot fetch anything, so it throws rather than silently returning an empty container.

Source

Thrown at packages/dev/core/src/SmartAssets/smartAssetManager.pure.ts:245

 * @param url - Optional URL. If provided, the key is registered first.
 * @param options - Optional loader hints and metadata for this asset.
 * @returns A promise resolving to the loaded AssetContainer.
 */
export async function LoadSmartAssetAsync(scene: Scene, key: string, url?: string, options?: SmartAssetLoadOptions): Promise<AssetContainer> {
    const manager = GetSmartAssetManager(scene);
    const internal = GetSmartAssetInternals(manager);
    const previousUrl = internal.urls.get(key);
    const { reloadSource, ...registrationOptions } = options ?? {};
    if (url) {
        RegisterSmartAsset(scene, key, url, registrationOptions);
    }
    if (reloadSource) {
        internal.reloadSources.set(key, reloadSource);
    }

    const resolvedUrl = internal.urls.get(key);
    if (!resolvedUrl) {
        throw new Error(`SmartAssetManager: Key "${key}" is not registered. Provide a URL to auto-register.`);
    }

    const existing = internal.containers.get(key);
    if (existing) {
        if (url && url !== previousUrl) {
            // URL changed — drop the stale container before fetching the new one
            // so callers don't get a surprise cached return for an updated URL.
            await UnloadSmartAssetAsync(scene, key);
        } else {
            return existing;
        }
    }

    return await LoadSmartAssetSceneFileAsync(manager, key, resolvedUrl, internal.options.get(key)?.extension);
}

/**
 * Loads all registered assets concurrently.

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Pass the URL so the key auto-registers: LoadSmartAssetAsync(scene, key, url).
  2. Check the key exists before loading with GetAllSmartAssets(scene).has(key); register it first via RegisterSmartAsset if missing.
  3. Verify the key string against the registered keys (typos/renames are the most common cause).
  4. Ensure you are using the SmartAssetManager for the correct Scene — registrations are per-scene and will not be found on a different scene's manager.
  5. If the key was intentionally unloaded, re-register it before the next load/reload call.

Example fix

// before
const container = await LoadSmartAssetAsync(scene, "player-model");
// after
if (!GetAllSmartAssets(scene).has("player-model")) {
    RegisterSmartAsset(scene, "player-model", "https://cdn.example.com/player.glb");
}
const container = await LoadSmartAssetAsync(scene, "player-model");
Defensive patterns

Strategy: validation

Validate before calling

function ensureSmartAssetRegistered(scene: Scene, key: string): boolean {
    return GetAllSmartAssets(scene).has(key);
}
// call site:
if (!ensureSmartAssetRegistered(scene, key)) {
    RegisterSmartAsset(scene, key, url);
}
const container = await LoadSmartAssetAsync(scene, key);

Try / catch

try {
    container = await LoadSmartAssetAsync(scene, key);
} catch (e) {
    if (e instanceof Error && e.message.includes('is not registered')) {
        container = await LoadSmartAssetAsync(scene, key, fallbackUrls[key]);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: LoadSmartAssetAsync(scene, key) with a key never registered via RegisterSmartAsset; calling with a key that was just removed by UnloadSmartAssetAsync (which deletes urls/options/containers for the key, see lines 206-210); a typo'd or renamed key; calling load before project deserialization populated the registry (e.g. DeserializeSmartAssetMap result not applied); loading on a different scene's manager than the one where assets were registered.

Common situations: Loading a saved project where the asset map failed to deserialize or was loaded into another scene; renaming an asset key in one place but not the other; calling ReloadSmartAssetAsync after the key was unloaded; hand-written load calls using keys from an older project file whose registrations were dropped.

Related errors


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