BabylonJS/Babylon.js · error

SmartAssetSerializer: Invalid asset map — expected an object

Error message

SmartAssetSerializer: Invalid asset map — expected an object.

What it means

DeserializeSmartAssetMap validates raw (typically JSON.parse'd) data against the smart asset map schema. The first check requires the input to be a non-null object; null, undefined, arrays-as-top-level (arrays still pass typeof 'object' — this check mainly catches null/primitives), strings, numbers, and booleans all throw this error. It guards against feeding the deserializer empty, truncated, or non-JSON payloads.

Source

Thrown at packages/dev/core/src/SmartAssets/smartAssetSerializer.ts:43

 * each loaded `AssetContainer` after load. Persisting it would risk staleness.
 */
export interface ISerializedSmartAssetMap {
    /** Schema version. Must be 1 for the current version. */
    readonly version: 1;

    /** Map of asset keys to their serialized entries. */
    readonly assets: Record<string, ISerializedSmartAssetEntry>;
}

/**
 * Validates and parses a serialized smart asset map document.
 * @param data - The raw data to validate (typically parsed JSON).
 * @returns The validated document.
 * @throws If the data does not conform to the expected schema.
 */
export function DeserializeSmartAssetMap(data: unknown): ISerializedSmartAssetMap {
    if (!data || typeof data !== "object") {
        throw new Error("SmartAssetSerializer: Invalid asset map — expected an object.");
    }

    const doc = data as Record<string, unknown>;

    if (doc.version !== 1) {
        throw new Error(`SmartAssetSerializer: Unsupported asset map version "${doc.version}". Expected version 1.`);
    }

    if (!doc.assets || typeof doc.assets !== "object" || Array.isArray(doc.assets)) {
        throw new Error("SmartAssetSerializer: Invalid asset map — 'assets' must be an object.");
    }

    const assets = doc.assets as Record<string, unknown>;
    for (const [key, entry] of Object.entries(assets)) {
        if (!entry || typeof entry !== "object") {
            throw new Error(`SmartAssetSerializer: Invalid entry for key "${key}" — expected an object.`);
        }
        const entryObj = entry as Record<string, unknown>;

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Parse the payload before deserializing: DeserializeSmartAssetMap(JSON.parse(rawText)).
  2. Check the fetch/read result for emptiness or HTTP errors before calling the deserializer.
  3. Handle first-run cases where no saved project exists (null from storage) by constructing a default { version: 1, assets: {} } map.
  4. Log/inspect the raw payload to confirm it is the expected project JSON and not an error page or message.

Example fix

// before
const doc = DeserializeSmartAssetMap(await response.text());
// after
const raw = await response.text();
if (!raw) {
    throw new Error("Project file is empty");
}
const doc = DeserializeSmartAssetMap(JSON.parse(raw));
Defensive patterns

Strategy: validation

Validate before calling

function isValidAssetMapPayload(data: unknown): data is Record<string, unknown> {
    return data !== null && typeof data === "object" && !Array.isArray(data);
}
// call site:
const parsed = JSON.parse(raw);
if (!isValidAssetMapPayload(parsed)) {
    throw new Error("Project file is corrupt or empty");
}
const doc = DeserializeSmartAssetMap(parsed);

Type guard

function isSmartAssetMapCandidate(data: unknown): data is Record<string, unknown> {
    return typeof data === "object" && data !== null;
}

Try / catch

let doc: ISerializedSmartAssetMap;
try {
    doc = DeserializeSmartAssetMap(parsed);
} catch (e) {
    if (e instanceof Error && e.message.includes('expected an object')) {
        doc = { version: 1, assets: {} }; // fall back to an empty project
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Passing JSON.parse(null/undefined/'') results into DeserializeSmartAssetMap; DeserializeProject receiving an empty file, an empty fetch response, or a 404/error body; passing a string of JSON instead of the parsed object; passing null explicitly as the data argument.

Common situations: A project file saved as empty due to a crashed write; a network layer returning an error string that got passed through unparsed; reading localStorage before the project was ever saved (null); calling the API with raw text fetched via response.text() instead of response.json().

Related errors


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