{"record":{"id":"4a5d83daf1608ee6","repo":"BabylonJS/Babylon.js","slug":"smartassetserializer-invalid-asset-map-assets","errorCode":null,"errorMessage":"SmartAssetSerializer: Invalid asset map — 'assets' must be an object.","messagePattern":"SmartAssetSerializer: Invalid asset map — 'assets' must be an object\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/SmartAssets/smartAssetSerializer.ts","lineNumber":53,"sourceCode":"/**\n * Validates and parses a serialized smart asset map document.\n * @param data - The raw data to validate (typically parsed JSON).\n * @returns The validated document.\n * @throws If the data does not conform to the expected schema.\n */\nexport function DeserializeSmartAssetMap(data: unknown): ISerializedSmartAssetMap {\n    if (!data || typeof data !== \"object\") {\n        throw new Error(\"SmartAssetSerializer: Invalid asset map — expected an object.\");\n    }\n\n    const doc = data as Record<string, unknown>;\n\n    if (doc.version !== 1) {\n        throw new Error(`SmartAssetSerializer: Unsupported asset map version \"${doc.version}\". Expected version 1.`);\n    }\n\n    if (!doc.assets || typeof doc.assets !== \"object\" || Array.isArray(doc.assets)) {\n        throw new Error(\"SmartAssetSerializer: Invalid asset map — 'assets' must be an object.\");\n    }\n\n    const assets = doc.assets as Record<string, unknown>;\n    for (const [key, entry] of Object.entries(assets)) {\n        if (!entry || typeof entry !== \"object\") {\n            throw new Error(`SmartAssetSerializer: Invalid entry for key \"${key}\" — expected an object.`);\n        }\n        const entryObj = entry as Record<string, unknown>;\n        if (typeof entryObj.url !== \"string\" || entryObj.url.length === 0) {\n            throw new Error(`SmartAssetSerializer: Invalid entry for key \"${key}\" — 'url' must be a non-empty string.`);\n        }\n    }\n\n    return data as ISerializedSmartAssetMap;\n}\n\n/**\n * Returns true for `data:`, `blob:`, or any URL with an absolute protocol.","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/SmartAssets/smartAssetSerializer.ts#L35-L71","documentation":"DeserializeSmartAssetMap validates the shape of a serialized smart-asset map document. After checking the version equals 1, it requires doc.assets to be a plain object (record of key -> entry). This error is thrown when 'assets' is missing, null, not an object, or is an Array, because the deserializer cannot iterate asset entries otherwise.","triggerScenarios":"Calling DeserializeSmartAssetMap with a parsed JSON doc where: doc.assets is undefined/omitted; doc.assets is null; doc.assets is an array (e.g. [{...},{...}] instead of {\"a\": {...}}); or doc.assets is a primitive like a string or number.","commonSituations":"Hand-edited or truncated asset-map JSON files exported from another tool; a producer exporting assets as a JSON array instead of a keyed map; an older/newer export format where the assets were stored under a different key (e.g. 'assetMap' or nested), leaving doc.assets undefined; template literal string interpolation passing the wrong object level (passing the whole project instead of doc.assets).","solutions":["Inspect the JSON document and ensure it has a top-level 'assets' key holding a plain object of key -> {url,...} entries.","If your data is an array of entries, convert it to a keyed object map before deserializing (e.g. Object.fromEntries(entries.map(e => [e.name, e]))).","Verify you are passing the correct document (the asset map doc with version:1 and assets), not a parent project object or a sub-field.","Re-export the asset map from the tool that produced it to regenerate a valid version-1 document."],"exampleFix":"// before\nconst doc = JSON.parse(raw);\nawait DeserializeSmartAssetMap(doc); // doc.assets missing / is an array\n\n// after\nconst parsed = JSON.parse(raw);\nconst doc = {\n  version: 1,\n  assets: Array.isArray(parsed.assets)\n    ? Object.fromEntries(parsed.assets.map(a => [a.name, a]))\n    : (parsed.assets ?? {})\n};\nawait DeserializeSmartAssetMap(doc);","handlingStrategy":"validation","validationCode":"function isValidAssetMapDoc(doc) {\n  return !!doc && typeof doc === \"object\" &&\n    doc.version === 1 &&\n    typeof doc.assets === \"object\" &&\n    doc.assets !== null &&\n    !Array.isArray(doc.assets);\n}\nif (!isValidAssetMapDoc(parsed)) throw new Error(\"Not a valid v1 smart-asset map document\");","typeGuard":"function isAssetMapDoc(doc): doc is { version: 1; assets: Record<string, unknown> } {\n  return typeof doc === \"object\" && doc !== null &&\n    (doc as any).version === 1 &&\n    typeof (doc as any).assets === \"object\" &&\n    (doc as any).assets !== null &&\n    !Array.isArray((doc as any).assets);\n}","tryCatchPattern":"try {\n  const map = DeserializeSmartAssetMap(doc);\n} catch (e) {\n  if (e.message.includes(\"'assets' must be an object\")) {\n    console.error(\"Asset map document malformed: missing or non-object 'assets'\", doc);\n  } else throw e;\n}","preventionTips":["Always produce asset maps through the library's SerializeSmartAssetMap rather than hand-writing JSON.","Round-trip test (serialize then deserialize) in CI to catch format regressions.","Never pass JSON arrays where a keyed map is expected; key entries by asset name.","Validate parsed JSON with a schema (zod/ajv) before deserialization."],"tags":["deserialization","validation","smart-assets","json"],"backgroundTag":"schema-validation-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}