{"record":{"id":"c3eb4cefc232f83b","repo":"stride3d/stride","slug":"external-variable-variable-name-not-found","errorCode":null,"errorMessage":"External variable {variable.Name} not found","messagePattern":"External variable (.+?) not found","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":1011,"sourceCode":"                {\n                    if (!compositionArrayAccesses.TryGetValue(memberAccess.Instance, out instanceMixinGroup!)\n                        && !mixinNode.Compositions.TryGetValue(memberAccess.Instance, out instanceMixinGroup!))\n                        throw new InvalidOperationException();\n                }\n\n                if (globalContext.ExternalVariables.TryGetValue(memberAccess.Member, out var variable))\n                {\n                    var shaderName = globalContext.ExternalShaders[variable.ShaderId];\n\n                    var shaderInfo = instanceMixinGroup.ShadersByName[shaderName];\n                    if (!shaderInfo.Variables.TryGetValue(variable.Name, out var variableInfo))\n                    {\n                        // Try as a stage variable\n                        if (!(instanceMixinGroup.Stage != null\n                            && instanceMixinGroup.Stage.ShadersByName.TryGetValue(shaderName, out shaderInfo)\n                            && shaderInfo.Variables.TryGetValue(variable.Name, out variableInfo)))\n                        {\n                            throw new InvalidOperationException($\"External variable {variable.Name} not found\");\n                        }\n                    }\n                    memberAccesses.Add(memberAccess.ResultId, variableInfo.Id);\n                }\n                else if (context.ReverseTypes[memberAccess.ResultType] is FunctionType functionType)\n                {\n                    // In case of functions, OpMemberAccessSDSL.Member could either be a OpFunction or a OpImportFunctionSDSL\n                    var functionId = memberAccess.Member;\n                    if (globalContext.ExternalFunctions.TryGetValue(memberAccess.Member, out var function))\n                    {\n                        // Process member call (composition)\n                        if (!instanceMixinGroup.MethodGroupsByName.TryGetValue((function.Name, functionType), out functionId)\n                            && (instanceMixinGroup.Stage == null || !instanceMixinGroup.Stage.MethodGroupsByName.TryGetValue((function.Name, functionType), out functionId)))\n                            throw new InvalidOperationException($\"Can't find function {function.Name} in current mixin\");\n                    }\n\n                    bool foundInStage = false;\n                    if (!instanceMixinGroup.MethodGroups.TryGetValue(functionId, out var methodGroupEntry))","sourceCodeStart":993,"sourceCodeEnd":1029,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L993-L1029","documentation":"While processing a member access to an external variable, the mixer resolves the variable in the current mixin's shader info. If not found there, it retries as a stage variable via instanceMixinGroup.Stage.ShadersByName and the stage shader's Variables. When both lookups fail, the referenced external variable does not exist in any resolvable scope.","triggerScenarios":"ShaderMixer constructor processes an OpMemberAccess whose member is an external variable; the variable name is absent from the mixin's Variables and, when Stage is non-null, from the stage shader's Variables (or Stage is null and shaderName lookup failed).","commonSituations":"Referencing a variable from another shader without the proper extern/attach declaration; typo in the variable name; the variable exists only in a base shader that is not attached as a stage; refactoring removed the variable while callers remain.","solutions":["Declare the variable (e.g. as extern or stage variable) in the shader that owns it, and ensure that shader is attached/composed.","Correct the variable name spelling at the access site.","Verify instanceMixinGroup.Stage is set when the variable is a stage variable.","Check that the variable is registered in the shader's Variables table (correct stream/type section)."],"exampleFix":"// before (variable not declared where accessed)\nfloat4 color = BaseColor;\n// after\nextern float4 BaseColor; // declared in the referenced shader, or access it via the composition path","handlingStrategy":"validation","validationCode":"// Verify the external variable is declared in the mixin or stage before mixing\nbool exists = shaderInfo.Variables.ContainsKey(varName)\n    || (instanceMixinGroup.Stage != null\n        && instanceMixinGroup.Stage.ShadersByName.TryGetValue(shaderName, out var si)\n        && si.Variables.ContainsKey(varName));\nif (!exists) throw new InvalidOperationException($\"Variable '{varName}' must be declared extern or as a stage variable\");","typeGuard":null,"tryCatchPattern":"try { var mixed = mixer.Process(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"External variable\") && ex.Message.Contains(\"not found\"))\n{\n    log.Error(ex, \"External variable unresolved; declare it extern/stage in the owning shader\");\n    throw;\n}","preventionTips":["Declare cross-shader variables as extern (or stage variables) at their point of definition.","Compile all shaders in CI to surface unresolved externals before runtime.","When renaming a variable, update every access site; keep declarations in one shared shader when widely used.","Verify base shaders that own the variables are actually attached to the composition."],"tags":["shader","sdsl","variable","scope-resolution"],"backgroundTag":"resource-not-found","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}