stride3d/stride · error · NotImplementedException

Shader compositions can only be indexed with a constant

Error message

Shader compositions can only be indexed with a constant: '{indexer2.Index}' is resolved at mix time, not at runtime.

What it means

Arrays of ShaderSymbol (shader compositions/mixin arrays) in SDSL are resolved at mix time, not at runtime, so they cannot be dynamically indexed by a runtime value. When the compiler encounters an IndexerExpression over a PointerType to an ArrayType of ShaderSymbol with an actual compiled index value, it throws this NotImplementedException. Only constant (compile-time) indexing of composition arrays is supported.

Solutions

  1. Use a compile-time constant index (literal or const value) when indexing shader composition arrays.
  2. Select the composition outside the shader via a branching composition/conditional mixin at effect-authoring time.
  3. Restructure so the runtime-selectable data lives in a regular (non-composition) array or a uniform buffer instead.
  4. Unroll the loop manually or use a static for-loop with constant bounds if a loop index is needed.

Example fix

// before (runtime index — not allowed)
comps[i].Shade(result);

// after (constant index / static selection)
const int i = 1;
comps[i].Shade(result);
Defensive patterns

Strategy: validation

Validate before calling

// composition arrays must be indexed by compile-time constants
if (arrayElemType is ShaderSymbol && !(indexExpr is LiteralExpression or { ValueType: ScalarType and ConstantValue != null }))
    throw new InvalidOperationException("Shader composition arrays require constant indices");

Type guard

static bool IsConstantIndex(Expression e) => e is LiteralExpression || (e.ValueType is ScalarType s && s.HasConstantValue);

Try / catch

try { CompileShader(source); }
catch (NotImplementedException e) when (e.Message.Contains("resolved at mix time"))
{
    // switch to a constant index or move selection to effect authoring
}

Prevention

When it happens

Trigger: Writing compositionsArray[i] where i is a runtime/mix-time variable rather than a compile-time constant, inside shader code operating on an array of shader compositions.

Common situations: Trying to loop over composition arrays with a runtime index, selecting a mixin variant based on a runtime uniform, or porting code from regular arrays (runtime-indexable) to composition arrays (constant-index only).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/8905383a6581be31. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Expression.cs:1363

                    break;
                // Array indexer for shader compositions: emit an OpAccessChain with a constant index,
                // which ShaderMixer.ProcessMemberAccessAndForeach resolves to compositions[index] at
                // mix time. A dynamic index has no composition to resolve to, hence the IntegerLiteral guard.
                case (PointerType { BaseType: ArrayType { BaseType: ShaderSymbol compositionType } } p, IndexerExpression { Index: IntegerLiteral } indexer):
                    {
                        if (compiler == null)
                        {
                            indexer.Index.ProcessSymbol(table);
                            accessor.Type = new PointerType(compositionType, p.StorageClass);
                            break;
                        }

                        var indexerValue = indexer.Index.CompileAsValue(table, compiler);
                        PushAccessChainId(accessChainIds, indexerValue.Id);
                        break;
                    }
                case (PointerType { BaseType: ArrayType { BaseType: ShaderSymbol } }, IndexerExpression indexer2):
                    throw new NotImplementedException(
                        $"Shader compositions can only be indexed with a constant: '{indexer2.Index}' is resolved at mix time, not at runtime.");
                // Array indexer for arrays
                case (PointerType { BaseType: ArrayType { BaseType: var t } } p, IndexerExpression indexer):
                    {
                        if (compiler == null)
                        {
                            indexer.Index.ProcessSymbol(table);
                            accessor.Type = new PointerType(t, p.StorageClass);
                            break;
                        }
                        var indexerValue = indexer.Index.CompileAsValue(table, compiler);
                        PushAccessChainId(accessChainIds, indexerValue.Id);
                        break;
                    }
                // Array indexer for vector/matrix
                case (PointerType { BaseType: VectorType or MatrixType } p, IndexerExpression indexer):
                    {
                        if (compiler == null)

View on GitHub (pinned to 96fad776d2)