BabylonJS/Babylon.js · error
Could not deserialize the following block definitions: ${blo
Error message
Could not deserialize the following block definitions: ${blockDefinitionsWhichCouldNotBeDeserialized.join(", ")} What it means
During v1 deserialization of a Smart Filter, each block definition is deserialized in parallel; block types that have no registered deserializer (or whose deserializer throws) are collected by name instead of failing immediately. If any failed, the whole deserialization is rejected listing the offending block types. It means the runtime does not know how to reconstruct one or more block types present in the serialized filter.
Source
Thrown at packages/dev/smartFilters/src/serialization/smartFilterDeserializer.ts:86
const blockNameMap = new Map<string, BaseBlock>();
// Deserialize the SmartFilter level data
smartFilter.comments = serializedSmartFilter.comments;
smartFilter.editorData = serializedSmartFilter.editorData;
// Deserialize the blocks
const blockDeserializationWork: Promise<void>[] = [];
const blockDefinitionsWhichCouldNotBeDeserialized: string[] = [];
serializedSmartFilter.blocks.forEach((serializedBlock: ISerializedBlockV1) => {
blockDeserializationWork.push(
this._deserializeBlockV1Async(smartFilter, serializedBlock, engine, blockDefinitionsWhichCouldNotBeDeserialized, blockIdMap, blockNameMap)
);
});
await Promise.all(blockDeserializationWork);
// If any block definitions could not be deserialized, throw an error
if (blockDefinitionsWhichCouldNotBeDeserialized.length > 0) {
throw new Error(`Could not deserialize the following block definitions: ${blockDefinitionsWhichCouldNotBeDeserialized.join(", ")}`);
}
// Deserialize the connections
serializedSmartFilter.connections.forEach((connection: ISerializedConnectionV1) => {
// Find the source block and its connection point's connectTo function
const sourceBlock = typeof connection.outputBlock === "string" ? blockNameMap.get(connection.outputBlock) : blockIdMap.get(connection.outputBlock);
if (!sourceBlock) {
throw new Error(`Source block ${connection.outputBlock} not found`);
}
const sourceConnectionPoint = sourceBlock.outputs.find((output) => output.name === connection.outputConnectionPoint);
if (!sourceConnectionPoint || typeof sourceConnectionPoint.connectTo !== "function") {
throw new Error(`Block ${connection.outputBlock} does not have an connection point named ${connection.outputConnectionPoint}`);
}
const sourceConnectToFunction = sourceConnectionPoint.connectTo.bind(sourceConnectionPoint);
// Find the target block and its connection point
const targetBlock = typeof connection.inputBlock === "string" ? blockNameMap.get(connection.inputBlock) : blockIdMap.get(connection.inputBlock);
View on GitHub (pinned to 0592b347b8)
Solutions
- Register the missing custom block definitions before deserializing (registerCustomBlockDefinition / importing the module that defines the block).
- Ensure the deserializer is given a runtime/dependency container that includes all block packages used by the filter.
- Check blockType names in the JSON against registered types for case/spelling drift after upgrades.
- Re-export the filter from the editor so it only uses available block types, or strip/replace the unsupported blocks.
- Log blockDefinitionsWhichCouldNotBeDeserialized content to identify exactly which registrations are missing.
Example fix
// before const filter = await SmartFilterDeserializer.DeserializeAsync(runtime, container, json); // unknown custom type // after import "./myCustomBlocks/registerAll"; // registers MyCustomBlock types const filter = await SmartFilterDeserializer.DeserializeAsync(runtime, container, json);
Defensive patterns
Strategy: validation
Validate before calling
function findUnregisteredTypes(serialized, registeredTypes) {
return (serialized.blockDefinitions ?? [])
.map((b) => b.blockType)
.filter((t) => t && !registeredTypes.has(t));
}
// call before DeserializeAsync; if result non-empty, register those types first Type guard
function allBlockTypesRegistered(serialized, registry) {
return (serialized.blockDefinitions ?? []).every((b) => !b.blockType || registry.has(b.blockType));
} Try / catch
try {
const filter = await SmartFilterDeserializer.DeserializeAsync(runtime, container, json);
} catch (e) {
const m = e.message.match(/Could not deserialize the following block definitions: (.+)/);
if (m) {
const missing = m[1].split(", ");
throw new Error(`Register these block types first: ${missing.join(", ")}`);
}
throw e;
} Prevention
- Import every custom block module before deserialization.
- Ship the same block packages used to author the filter.
- After upgrades, diff serialized blockType names against the registry.
- Pre-scan filter JSON block types against your registry as a smoke test.
- Avoid stripping 'unused' block modules from bundles used for deserialization.
When it happens
Trigger: Deserializing a .smartfilter JSON that references custom block types never registered via the block registry/registerCustomBlockDefinition, deserializing with a bundle that omits certain block packages, or version skew where the block type was renamed between versions.
Common situations: Sharing filter files that use third-party or custom blocks without shipping the registration code, loading filters created in the Smart Filter editor into a minimal runtime bundle, upgrading Babylon.js/smartFilters and block type names changing.
Related errors
- Source block ${connection.outputBlock} not found
- Block ${connection.outputBlock} does not have an connection
- `Target block ${connection.inputBlock} not found`
- `Block ${connection.inputBlock} does not have a connection p
- `No serializer was provided for a block of type ${block.bloc
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/87d7a0e172453e97.
Report an issue: GitHub.