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

  1. Register the missing custom block definitions before deserializing (registerCustomBlockDefinition / importing the module that defines the block).
  2. Ensure the deserializer is given a runtime/dependency container that includes all block packages used by the filter.
  3. Check blockType names in the JSON against registered types for case/spelling drift after upgrades.
  4. Re-export the filter from the editor so it only uses available block types, or strip/replace the unsupported blocks.
  5. 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

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


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/87d7a0e172453e97. Report an issue: GitHub.