{"record":{"id":"a57fdf09e1cf95c6","repo":"BabylonJS/Babylon.js","slug":"smartassetserializer-invalid-entry-for-key-key","errorCode":null,"errorMessage":"SmartAssetSerializer: Invalid entry for key \"${key}\" — expected an object.","messagePattern":"SmartAssetSerializer: Invalid entry for key \"(.+?)\" — expected an object\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/SmartAssets/smartAssetSerializer.ts","lineNumber":59,"sourceCode":"export 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.\n * @param url - The URL to inspect.\n * @returns Whether the URL is absolute or a data/blob URI.\n */\nexport function IsAbsoluteOrSpecialUrl(url: string): boolean {\n    return url.startsWith(\"data:\") || url.startsWith(\"blob:\") || Tools.IsAbsoluteUrl(url);\n}","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/SmartAssets/smartAssetSerializer.ts#L41-L77","documentation":"DeserializeSmartAssetMap iterates each key of doc.assets and requires every entry to be a non-null object. This error is thrown when an individual asset entry is null, undefined, or a primitive (string/number/boolean), so the deserializer cannot read fields like url from it.","triggerScenarios":"Any entry value inside doc.assets is null, undefined, a bare string URL (e.g. {\"logo\": \"https://...\"}), or a number/boolean. Detected in the for-loop over Object.entries(assets) when (!entry || typeof entry !== \"object\").","commonSituations":"Manually authored asset maps where someone wrote the URL string directly as the value instead of an object with a 'url' field; JSON produced by string templates that emitted null for missing assets; a schema change in an external asset pipeline that flattened entries from objects to strings; corrupted export where an entry was dropped to null.","solutions":["Open the asset-map JSON and fix the offending key so its value is an object, e.g. {\"logo\": {\"url\": \"https://...\"}} instead of {\"logo\": \"https://...\"}.","Remove null/undefined entries from doc.assets before deserializing, or filter them with a pre-validation pass.","If another tool produces this file, update or fix the exporter so each asset entry is serialized as an object with a url property.","Wrap deserialization in error handling that surfaces the offending key (it is included in the message) to locate and repair the entry quickly."],"exampleFix":"// before\nconst doc = { version: 1, assets: { logo: \"https://cdn/logo.png\", badge: null } };\nDeserializeSmartAssetMap(doc);\n\n// after\nconst doc = {\n  version: 1,\n  assets: {\n    logo: { url: \"https://cdn/logo.png\" },\n    badge: { url: \"https://cdn/badge.png\" }\n  }\n};\nDeserializeSmartAssetMap(doc);","handlingStrategy":"type-guard","validationCode":"const invalid = Object.entries(doc.assets ?? {}).filter(([, v]) => v === null || typeof v !== \"object\");\nif (invalid.length) throw new Error(`Asset entries must be objects: ${invalid.map(([k]) => k).join(\", \")}`);","typeGuard":"function isAssetEntry(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const map = DeserializeSmartAssetMap(doc);\n} catch (e) {\n  const m = e.message.match(/Invalid entry for key \"([^\"]+)\"/);\n  if (m) {\n    console.error(`Asset entry \"${m[1]}\" is not an object; fix or remove it in the asset map.`);\n  } else throw e;\n}","preventionTips":["Store URLs only inside entry objects ({url: ...}), never as bare strings.","Filter out null/placeholder entries at export time.","Schema-validate each asset entry before deserializing.","Keep exporter and consumer formats in lockstep; test exports against the deserializer."],"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"}