{"record":{"id":"d2b8dc6475ce18cb","repo":"BabylonJS/Babylon.js","slug":"symbol-symbol-is-reserved-and-cannot-be-used","errorCode":null,"errorMessage":"`Symbol \"${symbol}\" is reserved and cannot be used`","messagePattern":"`Symbol \"(.+?)\" is reserved and cannot be used`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/smartFilters/src/utils/buildTools/shaderConverter.ts","lineNumber":272,"sourceCode":"    log(`Uniforms found: ${JSON.stringify(uniforms)}`);\r\n    const consts = [...fragmentShader.matchAll(/\\S*const\\s+\\w*\\s+(\\w*)\\s*=.*;/g)].map((match) => match[1]);\r\n    log(`Consts found: ${JSON.stringify(consts)}`);\r\n    const constPropertyFriendlyNames = fragmentConstProperties.map((c) => c.friendlyName);\r\n    log(`Const properties found: ${JSON.stringify(constPropertyFriendlyNames)}`);\r\n    const defineNames = [...fragmentShader.matchAll(new RegExp(GetDefineRegExString, GetDefineRegExOptions))].map((match) => match[1]);\r\n    log(`Defines found: ${JSON.stringify(defineNames)}`);\r\n    const functionNames = [...fragmentShaderWithNoFunctionBodies.matchAll(new RegExp(GetFunctionHeaderRegExString, GetFunctionHeaderRegExOptions))].map((match) => match[1]);\r\n    log(`Functions found: ${JSON.stringify(functionNames)}`);\r\n\r\n    // Decorate the uniforms, consts, defines, and functions\r\n    const symbolsToDecorate = [...uniformNames, ...consts, ...constPropertyFriendlyNames, ...defineNames, ...functionNames];\r\n    let fragmentShaderWithRenamedSymbols = fragmentShader;\r\n    for (const symbol of symbolsToDecorate) {\r\n        if (!symbol) {\r\n            continue;\r\n        }\r\n        if (ReservedSymbols.indexOf(symbol) !== -1) {\r\n            throw new Error(`Symbol \"${symbol}\" is reserved and cannot be used`);\r\n        }\r\n        const regex = new RegExp(`(?<=\\\\W+)${symbol}(?=\\\\W+)`, \"gs\");\r\n        fragmentShaderWithRenamedSymbols = fragmentShaderWithRenamedSymbols.replace(regex, DecorateSymbol(symbol));\r\n    }\r\n    log(`${symbolsToDecorate.length} symbol(s) renamed`);\r\n\r\n    // Extract all the uniforms\r\n    const finalUniforms = [...fragmentShaderWithRenamedSymbols.matchAll(/^\\s*(uniform\\s.*)/gm)].map((match) => match[1]);\r\n\r\n    // Extract all the consts\r\n    const finalConsts = [...fragmentShaderWithRenamedSymbols.matchAll(/^\\s*(const\\s.*)/gm)].map((match) => match[1]);\r\n\r\n    // Extract all the defines\r\n    const finalDefines = [...fragmentShaderWithRenamedSymbols.matchAll(new RegExp(GetDefineRegExString, GetDefineRegExOptions))].map((match) => match[0]);\r\n\r\n    // Find the main input\r\n    const mainInputs = [...fragmentShaderWithRenamedSymbols.matchAll(/\\S*uniform.*\\s(\\w*);\\s*\\/\\/\\s*main/gm)].map((match) => match[1]);\r\n    if (mainInputs.length > 1) {\r","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/smartFilters/src/utils/buildTools/shaderConverter.ts#L254-L290","documentation":"During symbol decoration, ParseFragmentShader renames every uniform, const, define, and function name found in the shader. Before renaming, each symbol is checked against ReservedSymbols; if the shader uses a reserved word as a symbol name, decoration would corrupt the code, so this error is thrown naming the symbol.","triggerScenarios":"ParseFragmentShader on a shader whose uniform/const/define/function is named something in ReservedSymbols (e.g. a function named 'main', or a uniform colliding with a reserved runtime name). Any of fragmentShaderInfo/result entry points.","commonSituations":"Naming a helper function `main` alongside the real main; using common words like `position` or `output` that the framework reserves; porting existing GLSL code that already used framework-reserved identifiers.","solutions":["Rename the offending symbol to something not in ReservedSymbols (prefix it, e.g. `myMain` → `myHelperFn`).","Check the ReservedSymbols list in the smartFilters package and avoid all entries when authoring shaders.","If a define collides, namespace your defines (e.g. MYBLOCK_WHATEVER)."],"exampleFix":"// before\nvoid main(...) // main\n{ ... }\nvoid main() {} // duplicate/reserved helper\n// after\nvoid main(...) // main\n{ ... }\nvoid adjustColor() { ... }","handlingStrategy":"validation","validationCode":"const names = [\n  ...shader.matchAll(/\\buniform\\s+\\w+\\s+(\\w+)/g),\n  ...shader.matchAll(/\\bconst\\s+\\w+\\s+(\\w+)/g),\n  ...shader.matchAll(/\\b\\w+\\s+(\\w+)\\s*\\([^)]*\\)\\s*\\{/g),\n].map(m => m[1]);\nconst reserved = [\"main\",\"position\",\"output\",\"time\"]; // keep in sync with ReservedSymbols\nconst clash = names.filter(n => reserved.includes(n));\nif (clash.length) throw new Error(`Reserved symbols used: ${clash.join(\", \")}`);","typeGuard":"function isNotReserved(symbol: string): boolean {\n  return ReservedSymbols.indexOf(symbol) === -1;\n}","tryCatchPattern":"try {\n  const info = ParseFragmentShader(blockName, namespace, shader);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"is reserved and cannot be used\")) {\n    const sym = /Symbol \"(.+?)\"/.exec(e.message)?.[1];\n    // rename `sym` in the shader source and retry\n  } else throw e;\n}","preventionTips":["Keep the ReservedSymbols list imported and lint shader identifiers against it.","Avoid framework-common words when naming uniforms, consts, defines, and functions.","Prefix block-local symbols (e.g. `myBlock_`) to avoid collisions."],"tags":["shader","naming","reserved-word","glsl"],"backgroundTag":"reserved-identifier-conflict","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}