stride3d/stride · error · InvalidOperationException
External variable not found
Error message
External variable {variable.Name} not found What it means
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.
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).
Example fix
// before (variable not declared where accessed) float4 color = BaseColor; // after extern float4 BaseColor; // declared in the referenced shader, or access it via the composition path
Defensive patterns
Strategy: validation
Validate before calling
// Verify the external variable is declared in the mixin or stage before mixing
bool exists = shaderInfo.Variables.ContainsKey(varName)
|| (instanceMixinGroup.Stage != null
&& instanceMixinGroup.Stage.ShadersByName.TryGetValue(shaderName, out var si)
&& si.Variables.ContainsKey(varName));
if (!exists) throw new InvalidOperationException($"Variable '{varName}' must be declared extern or as a stage variable"); Try / catch
try { var mixed = mixer.Process(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("External variable") && ex.Message.Contains("not found"))
{
log.Error(ex, "External variable unresolved; declare it extern/stage in the owning shader");
throw;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Struct not found in shader
- Could not find compositions for expression
- Can't find function in current mixin
- Can't find method group info for
- Method was found but a base call can't be performed on a…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/c3eb4cefc232f83b.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:1011
{
if (!compositionArrayAccesses.TryGetValue(memberAccess.Instance, out instanceMixinGroup!)
&& !mixinNode.Compositions.TryGetValue(memberAccess.Instance, out instanceMixinGroup!))
throw new InvalidOperationException();
}
if (globalContext.ExternalVariables.TryGetValue(memberAccess.Member, out var variable))
{
var shaderName = globalContext.ExternalShaders[variable.ShaderId];
var shaderInfo = instanceMixinGroup.ShadersByName[shaderName];
if (!shaderInfo.Variables.TryGetValue(variable.Name, out var variableInfo))
{
// Try as a stage variable
if (!(instanceMixinGroup.Stage != null
&& instanceMixinGroup.Stage.ShadersByName.TryGetValue(shaderName, out shaderInfo)
&& shaderInfo.Variables.TryGetValue(variable.Name, out variableInfo)))
{
throw new InvalidOperationException($"External variable {variable.Name} not found");
}
}
memberAccesses.Add(memberAccess.ResultId, variableInfo.Id);
}
else if (context.ReverseTypes[memberAccess.ResultType] is FunctionType functionType)
{
// In case of functions, OpMemberAccessSDSL.Member could either be a OpFunction or a OpImportFunctionSDSL
var functionId = memberAccess.Member;
if (globalContext.ExternalFunctions.TryGetValue(memberAccess.Member, out var function))
{
// Process member call (composition)
if (!instanceMixinGroup.MethodGroupsByName.TryGetValue((function.Name, functionType), out functionId)
&& (instanceMixinGroup.Stage == null || !instanceMixinGroup.Stage.MethodGroupsByName.TryGetValue((function.Name, functionType), out functionId)))
throw new InvalidOperationException($"Can't find function {function.Name} in current mixin");
}
bool foundInStage = false;
if (!instanceMixinGroup.MethodGroups.TryGetValue(functionId, out var methodGroupEntry))View on GitHub (pinned to 96fad776d2)