{"record":{"id":"3eb809658ede3339","repo":"BabylonJS/Babylon.js","slug":"smartassetserializer-invalid-entry-for-key-key-3eb809","errorCode":null,"errorMessage":"SmartAssetSerializer: Invalid entry for key \"${key}\" — 'url' must be a non-empty string.","messagePattern":"SmartAssetSerializer: Invalid entry for key \"(.+?)\" — 'url' must be a non-empty string\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/SmartAssets/smartAssetSerializer.ts","lineNumber":63,"sourceCode":"\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}\n\n/**\n * Resolves an asset URL relative to a base URL.\n * Absolute URLs (http://, https://) and data URIs are returned as-is.","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/SmartAssets/smartAssetSerializer.ts#L45-L81","documentation":"Within DeserializeSmartAssetMap, after confirming an asset entry is an object, the deserializer requires entry.url to be a non-empty string. This error is thrown when the url property is missing, not a string (e.g. a number or object), or is an empty string, since the library cannot resolve the asset location without it.","triggerScenarios":"An entry in doc.assets such as {\"logo\": {}} (url omitted), {\"logo\": {\"url\": \"\"}}, or {\"logo\": {\"url\": 123}} / {\"url\": {...}} — checked via typeof entryObj.url !== \"string\" || entryObj.url.length === 0 for each key during Object.entries iteration.","commonSituations":"Export tools writing placeholder entries with empty url for assets that failed to upload; hand-written maps where the property was misnamed (uri, src, path) leaving url undefined; URL builders returning an empty string when an env var like CDN_BASE was unset; numeric IDs pasted into the url field.","solutions":["Add or correct the url field on the flagged entry (the key name is in the error message) so it is a non-empty string.","Check for property-name mismatches (uri/src/path/href) and rename to 'url', or map the field before deserializing.","Verify whatever builds the URL (env vars, base-CDN config) is not producing an empty string at export time.","Pre-validate the map yourself and fail early with your own message listing all invalid keys, rather than one at a time."],"exampleFix":"// before\nconst doc = { version: 1, assets: { logo: { uri: \"https://cdn/logo.png\" }, icon: { url: \"\" } } };\nDeserializeSmartAssetMap(doc);\n\n// after\nconst doc = {\n  version: 1,\n  assets: {\n    logo: { url: \"https://cdn/logo.png\" },\n    icon: { url: \"https://cdn/icon.png\" }\n  }\n};\nDeserializeSmartAssetMap(doc);","handlingStrategy":"validation","validationCode":"const badUrls = Object.entries(doc.assets ?? {})\n  .filter(([k, v]) => !v || typeof v !== \"object\" || typeof v.url !== \"string\" || v.url.length === 0)\n  .map(([k]) => k);\nif (badUrls.length) throw new Error(`Entries with missing/empty url: ${badUrls.join(\", \")}`);","typeGuard":"function hasUrl(v: unknown): v is { url: string } {\n  return typeof v === \"object\" && v !== null &&\n    typeof (v as { url?: unknown }).url === \"string\" &&\n    (v as { url: string }).url.length > 0;\n}","tryCatchPattern":"try {\n  const map = DeserializeSmartAssetMap(doc);\n} catch (e) {\n  const m = e.message.match(/key \"([^\"]+)\" — 'url' must be a non-empty string/);\n  if (m) {\n    console.error(`Asset \"${m[1]}\" has no valid url; check exporter output / URL builder.`);\n  } else throw e;\n}","preventionTips":["Use a single URL-builder helper so empty-string URLs (unset env/base URL) are caught early.","Standardize on the 'url' property name; reject uri/src/path aliases at export time.","Add a lint/schema check requiring a non-empty url string on every asset entry.","Validate the exported asset map in CI before publishing."],"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"}