{"record":{"id":"eb40efbcbf1b0a42","repo":"BabylonJS/Babylon.js","slug":"could-not-find-a-blocktype","errorCode":null,"errorMessage":"Could not find a blockType","messagePattern":"Could not find a blockType","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/smartFilters/src/serialization/importCustomBlockDefinition.ts","lineNumber":41,"sourceCode":"        return ImportAnnotatedGlsl(serializedData);\r\n    } else {\r\n        // Assume this is a serialized JSON object\r\n        const blockDefinition = JSON.parse(serializedData);\r\n\r\n        // Some old SmartFilters didn't have a format property - default to smartFilter if missing\r\n        if (blockDefinition.format === undefined) {\r\n            blockDefinition.format = \"smartFilter\";\r\n        }\r\n\r\n        // SmartFilters can be serialized without a blockType\r\n        // By convention, we use the SmartFilter name as the blockType when importing them as SerializedBlockDefinitions\r\n        if (blockDefinition.format === \"smartFilter\" && blockDefinition.name && !blockDefinition.blockType) {\r\n            blockDefinition.blockType = blockDefinition.name;\r\n        }\r\n\r\n        // Validation\r\n        if (!blockDefinition.blockType) {\r\n            throw new Error(\"Could not find a blockType\");\r\n        }\r\n\r\n        return blockDefinition;\r\n    }\r\n}\r\n\r\n/**\r\n * Converts a fragment shader .glsl file to an SerializedBlockDefinition instance for use\r\n * as a CustomShaderBlock. The .glsl file must contain certain annotations to be imported.\r\n * See readme.md for more information.\r\n * @param fragmentShader - The contents of the .glsl fragment shader file\r\n * @returns The serialized block definition\r\n */\r\nfunction ImportAnnotatedGlsl(fragmentShader: string): SerializedShaderBlockDefinition {\r\n    setLogger(Logger);\r\n    const fragmentShaderInfo = ParseFragmentShader(fragmentShader);\r\n\r\n    if (!fragmentShaderInfo.blockType) {\r","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/smartFilters/src/serialization/importCustomBlockDefinition.ts#L23-L59","documentation":"importCustomBlockDefinition validates a serialized custom block definition and requires a blockType that identifies the block in the registry. The only inference performed is using the definition's name when format is \"smartFilter\"; for any other format (e.g. GLSL annotated shaders, where blockType comes from parsing the shader), a missing blockType is a hard validation failure.","triggerScenarios":"Calling ImportCustomBlockDefinition with a definition whose blockType is undefined/null and either format is not \"smartFilter\" or name is also missing/empty — e.g. hand-written JSON missing the blockType field, or an annotated-GLSL definition (format \"glsl\") whose shader never got blockType set.","commonSituations":"Copying a block definition between filters and dropping required fields, authoring custom block JSON by hand, schema version drift where older exports lacked blockType, or GLSL shaders parsed without a blockType annotation.","solutions":["Add a blockType field to the serialized block definition JSON.","If format is \"smartFilter\", ensure name is set so it can be inferred as blockType.","If the definition is GLSL-based, include the blockType annotation in the shader source so parsing yields it.","Validate the definition shape before import (see defense validationCode).","Re-export from the tooling version that emits blockType if working with legacy files."],"exampleFix":"// before\nconst def = { name: \"MyBlock\", format: \"smartFilter\" }; // blockType missing, ok only via name\nconst def2 = { format: \"glsl\" }; // throws\n// after\nconst def2 = { blockType: \"MyBlock\", format: \"glsl\" };","handlingStrategy":"validation","validationCode":"function validateBlockDefinition(def) {\n  const hasType = !!def.blockType || (def.format === \"smartFilter\" && !!def.name);\n  if (!hasType) throw new Error(\"Block definition needs blockType (or name when format is smartFilter)\");\n  return def;\n}","typeGuard":"function hasBlockType(d) {\n  return typeof d === \"object\" && d !== null &&\n    (typeof d.blockType === \"string\" && d.blockType.length > 0 ||\n     (d.format === \"smartFilter\" && typeof d.name === \"string\" && d.name.length > 0));\n}","tryCatchPattern":"try {\n  const def = ImportCustomBlockDefinition(rawDef);\n} catch (e) {\n  if (e.message === \"Could not find a blockType\") {\n    throw new Error(`Definition '${rawDef?.name ?? \"?\"}' is missing blockType — fix the JSON before import`);\n  }\n  throw e;\n}","preventionTips":["Always include blockType in serialized custom block definitions.","For smartFilter-format definitions, ensure name is present so it can serve as blockType.","For GLSL definitions, keep the blockType annotation in the shader source.","Schema-validate exported filter JSON before import.","Regenerate legacy definitions with the current tooling version."],"tags":["smart-filters","serialization","validation","custom-blocks"],"backgroundTag":"missing-required-field","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}