BabylonJS/Babylon.js · error · Error
`Symbol "${symbol}" is reserved and cannot be used`
Error message
`Symbol "${symbol}" is reserved and cannot be used` What it means
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.
Source
Thrown at packages/dev/smartFilters/src/utils/buildTools/shaderConverter.ts:272
log(`Uniforms found: ${JSON.stringify(uniforms)}`);
const consts = [...fragmentShader.matchAll(/\S*const\s+\w*\s+(\w*)\s*=.*;/g)].map((match) => match[1]);
log(`Consts found: ${JSON.stringify(consts)}`);
const constPropertyFriendlyNames = fragmentConstProperties.map((c) => c.friendlyName);
log(`Const properties found: ${JSON.stringify(constPropertyFriendlyNames)}`);
const defineNames = [...fragmentShader.matchAll(new RegExp(GetDefineRegExString, GetDefineRegExOptions))].map((match) => match[1]);
log(`Defines found: ${JSON.stringify(defineNames)}`);
const functionNames = [...fragmentShaderWithNoFunctionBodies.matchAll(new RegExp(GetFunctionHeaderRegExString, GetFunctionHeaderRegExOptions))].map((match) => match[1]);
log(`Functions found: ${JSON.stringify(functionNames)}`);
// Decorate the uniforms, consts, defines, and functions
const symbolsToDecorate = [...uniformNames, ...consts, ...constPropertyFriendlyNames, ...defineNames, ...functionNames];
let fragmentShaderWithRenamedSymbols = fragmentShader;
for (const symbol of symbolsToDecorate) {
if (!symbol) {
continue;
}
if (ReservedSymbols.indexOf(symbol) !== -1) {
throw new Error(`Symbol "${symbol}" is reserved and cannot be used`);
}
const regex = new RegExp(`(?<=\\W+)${symbol}(?=\\W+)`, "gs");
fragmentShaderWithRenamedSymbols = fragmentShaderWithRenamedSymbols.replace(regex, DecorateSymbol(symbol));
}
log(`${symbolsToDecorate.length} symbol(s) renamed`);
// Extract all the uniforms
const finalUniforms = [...fragmentShaderWithRenamedSymbols.matchAll(/^\s*(uniform\s.*)/gm)].map((match) => match[1]);
// Extract all the consts
const finalConsts = [...fragmentShaderWithRenamedSymbols.matchAll(/^\s*(const\s.*)/gm)].map((match) => match[1]);
// Extract all the defines
const finalDefines = [...fragmentShaderWithRenamedSymbols.matchAll(new RegExp(GetDefineRegExString, GetDefineRegExOptions))].map((match) => match[0]);
// Find the main input
const mainInputs = [...fragmentShaderWithRenamedSymbols.matchAll(/\S*uniform.*\s(\w*);\s*\/\/\s*main/gm)].map((match) => match[1]);
if (mainInputs.length > 1) {
View on GitHub (pinned to 0592b347b8)
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).
Example fix
// before
void main(...) // main
{ ... }
void main() {} // duplicate/reserved helper
// after
void main(...) // main
{ ... }
void adjustColor() { ... } Defensive patterns
Strategy: validation
Validate before calling
const names = [
...shader.matchAll(/\buniform\s+\w+\s+(\w+)/g),
...shader.matchAll(/\bconst\s+\w+\s+(\w+)/g),
...shader.matchAll(/\b\w+\s+(\w+)\s*\([^)]*\)\s*\{/g),
].map(m => m[1]);
const reserved = ["main","position","output","time"]; // keep in sync with ReservedSymbols
const clash = names.filter(n => reserved.includes(n));
if (clash.length) throw new Error(`Reserved symbols used: ${clash.join(", ")}`); Type guard
function isNotReserved(symbol: string): boolean {
return ReservedSymbols.indexOf(symbol) === -1;
} Try / catch
try {
const info = ParseFragmentShader(blockName, namespace, shader);
} catch (e) {
if (e instanceof Error && e.message.includes("is reserved and cannot be used")) {
const sym = /Symbol "(.+?)"/.exec(e.message)?.[1];
// rename `sym` in the shader source and retry
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- `Consts must have a name: '${constLine}'`
- "Const line not found"
- `Consts must have a name, type, and a default value: '${cons
- `Consts must have a value: '${constLine}'`
- `Unsupported const property type: '${type}'`
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/d2b8dc6475ce18cb.
Report an issue: GitHub.