stride3d/stride · error · InvalidOperationException

Hull shader patch constant function

Error message

Hull shader patch constant function {patchConstantFuncName} was not found

What it means

For a hull shader, InterfaceProcessor.ResolveHullPatchConstantEntryPoint resolves the patch constant function named by the patchconstantfunc attribute in the symbol table. If the named function does not exist as an entry point, it throws because hull stage processing needs the patch constant stage to evaluate per-patch constants.

Solutions

  1. Make the patchconstantfunc name match the actual function in the shader (fix spelling/casing)
  2. Include the mixin/class containing the patch constant function in the shader composition
  3. Ensure the patch constant function is declared as an entry-point-eligible method so it lands in the symbol table

Example fix

// before
[patchconstantfunc("PatchConstantFunc")] // function is actually named HSConstants
// after
[patchconstantfunc("HSConstants")]
Defensive patterns

Strategy: validation

Validate before calling

var hs = composition.Classes.SelectMany(c => c.GetMethods()).First(m => m.Name == "HSMain");
var patchFuncName = (string?)hs.GetCustomAttributes()
    .FirstOrDefault(a => a.Type.Name.Contains("patchconstantfunc"))?.ConstructorArguments.FirstOrDefault().Value;
if (patchFuncName != null &&
    !composition.Classes.SelectMany(c => c.GetMethods()).Any(m => m.Name == patchFuncName))
    throw new InvalidOperationException($"Patch constant function '{patchFuncName}' not found in composition.");

Try / catch

try
{
    mixer.MergeSDSL(shaderSource, options, log, out var bytecode, out _, out _, out _);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("patch constant function"))
{
    log.Error("Hull patch constant function missing: " + ex.Message);
}

Prevention

When it happens

Trigger: MergeSDSL with a hull shader whose patchconstantfunc attribute names a function (e.g. 'HSPatchConstant') that is not present as an entry point in the merged SPIR-V symbol table — ResolveEntryPoint returns null.

Common situations: Typo in the patchconstantfunc attribute value; renaming/refactoring the patch constant function without updating the attribute; the patch constant function lives in a mixin not included in the composition; porting HLSL where the function name casing differs.

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


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/InterfaceProcessor.cs:745

                        {
                            Target: int target,
                            Decoration: Decoration.PatchConstantFuncSDSL,
                            Value: string funcName
                        } && target == overrideChain[index])
                    {
                        patchConstantFuncName = funcName;
                        break;
                    }
                }
            }

            Symbol? patchConstantEntryPoint = null;
            if (patchConstantFuncName != null)
            {
                // Resolve the patch constant function
                patchConstantEntryPoint = ResolveEntryPoint(table, patchConstantFuncName);
                if (patchConstantEntryPoint == null)
                    throw new InvalidOperationException($"Hull shader patch constant function {patchConstantFuncName} was not found");
            }

            return patchConstantEntryPoint;
        }
    }
}

View on GitHub (pinned to 96fad776d2)