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
- Parse the payload before deserializing: DeserializeSmartAssetMap(JSON.parse(rawText)).
- Check the fetch/read result for emptiness or HTTP errors before calling the deserializer.
- Handle first-run cases where no saved project exists (null from storage) by constructing a default { version: 1, assets: {} } map.
- 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
- Always JSON.parse before calling DeserializeSmartAssetMap — never pass raw text.
- Check file size/emptiness and HTTP status before parsing fetched project files.
- Treat null from localStorage/first-run as 'no project' and build a default map.
- Add a smoke test round-tripping Serialize -> Deserialize to catch payload regressions.
- Guard against top-level arrays if your producer could emit them.
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
- SmartAssetSerializer: Unsupported asset map version "${doc.v
- SmartAssetSerializer: Invalid asset map — 'assets' must be a
- SmartAssetSerializer: Invalid entry for key "${key}" — expec
- SmartAssetSerializer: Invalid entry for key "${key}" — 'url'
- Could not deserialize input block, unknown input type
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/139b62d6dd8d0176.
Report an issue: GitHub.