BabylonJS/Babylon.js · error
Helper function ${funcName} in blockType ${block.blockType}
Error message
Helper function ${funcName} in blockType ${block.blockType} accesses uniform(s) ${uniformsAccessed.join(", ")} which is not supported. Pass them in instead. What it means
During optimization, SmartFilterOptimizer._processHelperFunctions inlines GLSL helper functions. A helper may only access uniforms that are passed in as parameters; if, after subtracting the function's parameters, it still references uniform symbols, the optimizer cannot safely inline it and throws this error naming the offending uniforms.
Source
Thrown at packages/dev/smartFilters/src/optimization/smartFilterOptimizer.ts:360
for (const remappedSymbol of this._remappedSymbols) {
if (
remappedSymbol.type === "uniform" &&
remappedSymbol.owners[0] &&
remappedSymbol.owners[0].blockType === block.blockType &&
func.code.includes(remappedSymbol.remappedName)
) {
uniformsAccessed.push(remappedSymbol.remappedName);
}
}
// Strip out any matches which are actually function params
const functionParams = func.params ? func.params.split(",").map((p) => p.trim().split(" ")[1]) : [];
uniformsAccessed = uniformsAccessed.filter((u) => !functionParams.includes(u));
// If it accessed any uniforms, throw an error
if (uniformsAccessed.length > 0) {
uniformsAccessed = uniformsAccessed.map((u) => (u[0] === DecorateChar ? UndecorateSymbol(u) : u));
throw new Error(
`Helper function ${funcName} in blockType ${block.blockType} accesses uniform(s) ${uniformsAccessed.join(", ")} which is not supported. Pass them in instead.`
);
}
// Look to see if we have an exact match including parameters of this function in the list of remapped symbols
const existingFunctionExactOverload = this._remappedSymbols.find(
(s) => s.type === "function" && s.name === funcName && s.params === func.params && s.owners[0] && s.owners[0].blockType === block.blockType
);
// Look to see if we already have this function in the list of remapped symbols, regardless of parameters
const existingFunction = this._remappedSymbols.find((s) => s.type === "function" && s.name === funcName && s.owners[0] && s.owners[0].blockType === block.blockType);
// Get or create the remapped name, ignoring the parameter list
let remappedName = existingFunction?.remappedName;
let createdNewName = false;
if (!remappedName) {
remappedName = DecorateSymbol(this._makeSymbolUnique(funcName));
createdNewName = true;
View on GitHub (pinned to 0592b347b8)
Solutions
- Rewrite the helper function to take the uniform value as a parameter and pass it at each call site.
- Move the uniform read outside the helper into the main function body.
- Verify the helper's parameter names match the uniform names exactly (params are parsed from the signature) so they are correctly excluded.
- Undecorate/decorate handling: ensure uniform names after DecorateChar processing match the declared parameters.
Example fix
// before (GLSL)
float brighten(vec2 uv) { return texture2D(uTexture, uv).r * uIntensity; }
// after
float brighten(vec2 uv, float intensity) { return texture2D(uTexture, uv).r * intensity; }
// call: brighten(uv, uIntensity); Defensive patterns
Strategy: validation
Validate before calling
// Static check on block GLSL: helper functions must not reference uniform names not in their params
const uniformNames = new Set(collectUniforms(shaderCode));
for (const fn of collectFunctions(shaderCode)) {
const used = collectIdentifiers(fn.body).filter(id => uniformNames.has(id));
const params = new Set(fn.params);
const offending = used.filter(u => !params.has(u));
if (offending.length) throw new Error(`Helpers must receive uniforms as params: ${offending}`);
} Type guard
null
Try / catch
try {
await SmartFilterOptimizer.OptimizeAsync(engine, filter, texture);
} catch (e) {
if (e.message.includes("accesses uniform")) {
// parse uniform names from the message and fix the block's GLSL
} else throw e;
} Prevention
- Write block helper functions to take every uniform they need as an explicit parameter.
- Match helper parameter names exactly to the uniform names so the optimizer can exclude them.
- Lint custom GLSL for direct uniform references inside function bodies before shipping blocks.
When it happens
Trigger: A block's GLSL (from getCustomShaderCode or a custom block) declares a helper function whose body reads a uniform variable directly instead of receiving it as a function argument, and the optimizer processes that function.
Common situations: Writing a custom SmartFilter block with hand-authored GLSL helpers that close over uniforms; porting shader code that assumes global uniform access; renaming uniforms so parameter matching fails.
Related errors
- Could not optimize blockType ${block.blockType} because a te
- VERTEX SHADER ${log}
- FRAGMENT SHADER ${log}
- ${error}
- Shader bindings not set!
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/b1a9f6851681387a.
Report an issue: GitHub.