BabylonJS/Babylon.js · error · Error

Invalid FlowGraph block module for ${blockName}

Error message

Invalid FlowGraph block module for ${blockName}

What it means

_LoadBlock dynamically imports a block's module and looks for the block class export and its RegisterFlowGraph* side-effect function. If the module doesn't export a usable block and/or register function, it throws 'Invalid FlowGraph block module for <blockName>'. This indicates the dynamic module failed to provide the expected surface.

Source

Thrown at packages/dev/core/src/FlowGraph/Blocks/flowGraphBlockFactory.ts:45

function _IsFlowGraphBlockConstructor(value: unknown): value is typeof FlowGraphBlock {
    return typeof value === "function" && value.prototype instanceof FlowGraphBlock;
}

async function _LoadBlock(modulePromise: Promise<object>, blockName: string): Promise<typeof FlowGraphBlock> {
    const module = await modulePromise;
    let block: typeof FlowGraphBlock | undefined;
    let register: (() => void) | undefined;

    for (const [exportName, value] of Object.entries(module)) {
        if (exportName === blockName && _IsFlowGraphBlockConstructor(value)) {
            block = value;
        } else if (exportName.startsWith("RegisterFlowGraph") && typeof value === "function") {
            register = value;
        }
    }

    if (!block || !register) {
        throw new Error(`Invalid FlowGraph block module for ${blockName}`);
    }

    register();
    if (blockName === "FlowGraphPlayAnimationBlock") {
        const { RegisterAnimationGroup } = await import("../../Animations/animationGroup.pure");
        RegisterAnimationGroup();
    }

    return block;
}

/**
 * a function to get a factory function for a block.
 * @param blockName the block name to initialize. If the block comes from an external module, the name should be in the format "module/blockName"
 * @returns an async factory function that will return the block class when called.
 */
// eslint-disable-next-line @typescript-eslint/naming-convention
export function blockFactory(blockName: FlowGraphBlockNames | string): () => Promise<typeof FlowGraphBlock> {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the block name matches an existing exported FlowGraph block for the installed core version
  2. Ensure your bundler preserves the dynamic import module's named exports (don't tree-shake the FlowGraph Blocks modules)
  3. Import and call the block's Register function explicitly at startup instead of relying on dynamic loading

Example fix

// before
const block = await blockFactory('FlowGraphTypoBlock', config); // invalid module
// after
const block = await blockFactory('FlowGraphSetVariableBlock', config);
Defensive patterns

Strategy: validation

Validate before calling

const mod = await import(blockPath);
if (typeof mod[blockName] !== 'function') throw new Error('Module missing block export: ' + blockName);

Try / catch

try { block = await blockFactory(name, cfg); } catch (e) { if (e.message.startsWith('Invalid FlowGraph block module')) { /* register block explicitly or skip */ } else throw e; }

Prevention

When it happens

Trigger: blockFactory requests a blockName whose module exists but lacks the expected exports (block class not exported, or no Register* function), e.g. a renamed internal export or a stub/failed dynamic import result.

Common situations: Version mismatch where a block was renamed or removed; custom bundling/tree-shaking stripping named exports; typos in block names that resolve to the wrong module; broken dynamic-import chunking in builds.

Related errors


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