Diagnostic Codes

Every diagnostic ShadowDusk emits carries a code. This page is the complete registry: look up the code you saw in your build output to find out what triggered it.

Two things worth knowing before you read the table:

  • Codes from the underlying compilers are passed through verbatim and are not listed here. When DXC, d3dcompiler_47, or vkd3d-shader rejects your shader, you get that compiler's own words, unedited, along with the file, line, and column it reported. ShadowDusk never rewrites or summarizes a diagnostic it did not produce.
  • SD0400–SD0499 are always warnings. They flag constructs that compile successfully but are known to fail or silently misbehave at runtime on narrower OpenGL stacks (WebGL, ANGLE, strict Mesa drivers), where the engine's own error is a generic draw-time exception. They never reject a shader.
  • Some codes outside that range are warnings too, marked Warning in the table: SD0007 (a ShaderToy conversion adjustment), SD0008 (an #include that only resolves because the file system ignores case), SD0009 (the managed preprocessed view of the technique list could not be built, so the techniques are read from the raw source; its OpenGL sampler-register form is an error), SD0017 (a global initializer ShadowDusk cannot evaluate, so that parameter's default would be zero), SD0029 (CLI only: an .xnb requested with no profile, so it holds a DirectX_11 effect), SD0104 (an unrecognized vertex-input semantic defaulted to TextureCoordinate, exactly as mgfxc defaults and warns), SD0220 and SD0226 (build warnings raised in your own build when it resolves a Vortice.Dxc or Silk.NET SPIRV-Cross native other than the pinned one), SD0222 (a DirectX 12 texture array, reflected as one parameter on the first slot exactly as mgfxc reflects it, with the other elements unreachable in the engine; a sampler array is the error SD0224 instead, on DirectX 11 and 12, because mgfxc refuses it in its own parser), SD0230 (DirectX 11: a shader's legacy-sampler texture slots could not be proven to match mgfxc's, so the declaration-order slots are kept), SD0235 (Vulkan: a texture sampled through a second sampler gets a second descriptor), SD0614 (SkSL converter: a synthesized uniform your draw code must set) and SD0637 (raylib converter: sampler_state entries raylib cannot carry). Like every warning, they never gate output.

To see everything wrong with a shader in one pass, including warnings and across several targets, call ValidateAsync instead of compiling. See the In-Memory Quickstart.

ShadowDusk diagnostic code registry

The central registry of every diagnostic code ShadowDusk itself emits. Every code maps to exactly one condition (one historical exception is flagged below). When adding a new error, pick an unused number from the matching range and add it here in the same change.

Codes from the underlying compilers (DXC, d3dcompiler_47, vkd3d-shader) are passed through verbatim (constraint 5: fail loudly, no reformatting) and are not listed here. Only their location is ShadowDusk's to fix: vkd3d-shader's own file/line/column are re-mapped onto the author's source by Vkd3dSourceLocator (issue #202 — vkd3d 2.1's coordinates drift with skipped #if arms and every template-implemented intrinsic call), while the message text and the code (E5017, E5000, …) stay exactly as the compiler emitted them. The raw text printed under the summary is treated the same way, line by line: its file:line:col: prefixes move onto the author's source and everything after them stays verbatim.

Ranges

Range Owner
FX0001–FX0099 FX9 pre-parser (FxPreParser / FxLexer)
SD0000 CLI informational notes (severity Note, never a failure)
SD0001–SD0009 Preprocessor (#include handling), input-format detection, source-provenance notes, and the ShaderToy/GLSL front end
SD0010–SD0019 Pipeline-level effect validation
SD0020–SD0029 MGFX writer range guards, container/target guards, and source-level target-binding guards (e.g. SD0028)
SD0100–SD0199 Reflection / transpilation backends
SD0200–SD0299 Platform / backend availability
SD0300–SD0399 FNA (fx_2_0) target
SD0400–SD0499 GL portability lint (GlslPortabilityAnalyzer) — always warnings, never errors
SD0500–SD0599 MGCB content-processor plugin
SD0600–SD0609 Slang input frontend (SlangFrontend and its passes)
SD0610–SD0619 SkSL converter (SkslConverter / SkslGlslMapper)
SD0620–SD0629 Real-slangc Slang compile route (ShadowDusk.Slang.SlangCompiler)
SD0630–SD0639 raylib converter (RaylibConverter / RaylibGlslMapper)
SD0640–SD0649 Real-slangc Slang compile route, continued (SD0620–SD0629 is full): the names slangc generates (SlangcHoistedResourceNames)
SD0650–SD0659 Library input-format routing (ShaderConverter, over ShaderFormatDetector); SD0001–SD0009 is full
SD1900–SD1999 Browser/WASM host backends
X0000–X0099 CLI and pipeline general errors (mgfxc-style)

FX — FX9 pre-parser

Code Meaning
FX0001 Unexpected token during FX9 parsing.
FX0002 Source ended before the current construct was closed.
FX0003 Malformed compile expression in a pass.
FX0004 Unrecognized shader profile string.
FX0005 Duplicate technique name, decided on the preprocessed source (the same name once per #if branch is legal). Anonymous techniques are all named "" and never collide: two of them compile, as in mgfxc, KNI's pipeline and fxc (since 0.23.0).
FX0006 Duplicate pass name within a technique.
FX0007 Annotation block opened but never closed.
FX0008 Missing required ; after a statement.
FX0009 sampler_state block opened but never closed.
FX0010 Unrecognized render-state key (non-fatal).
FX0011 Unknown character in effect source (e.g. @, `).
FX0012 Legacy D3D9 sampling intrinsic the SM4 rewrite cannot convert: the 1D, 3D and cube families (tex1D…, tex3D…, texCUBE…, which need a resource type the rewrite does not synthesize), or a tex2Dlod / tex2Dbias / tex2Dproj call with other than two arguments (a call whose rewrite depends on the #if branch is redone from the preprocessed source; FX0012 only if that cannot be built). tex2D, tex2Dgrad, tex2Dlod, tex2Dbias and tex2Dproj are rewritten. Never raised for FNA.
FX0013 An SM4+ resource or sampler type (e.g. SamplerComparisonState) appeared in a shader targeting FNA's D3D9 fx_2_0 profile, where no SM1–3 lowering exists. Raised before the source reaches vkd3d, which does not reject these cleanly (a SamplerComparisonState makes its SM1 lowering take the whole process down with an access violation).
FX0014 A pass assigns HullShader, DomainShader, GeometryShader, or ComputeShader. MonoGame's and KNI's Effect model exactly two shader stages, so no compiler can produce a loadable effect containing one — a consumer-runtime limit, not a ShadowDusk gap (mgfxc refuses the same inputs). Replaces the nonsense FX0008 "missing ;" these used to produce. See plan/DONE/PHASE-58-extended-shader-stages.md for the measured evidence and the conversion question.

SD — ShadowDusk pipeline

Code Meaning Emitted by
SD0000 Note. Informational output from the CLI, never a failure — currently the drivable effect parameters listed by --print-uniforms. PipelineRunner
SD0001 #include file not found on any search path. ShaderError.IncludeNotFound
SD0002 Circular #include (true cycle on the include stack; a diamond include is legal). ShaderError.CircularInclude
SD0003 Note. A ShaderToy/GLSL input was converted to .fx and that generated HLSL failed to compile — the diagnostics that follow refer to the generated source, not your original line numbers. PipelineRunner
SD0004 #include file was found on a search path but could not be read (locked, access denied, or deleted between the existence check and the read). FileSystemIncludeResolver
SD0005 Input format could not be detected. CLI (InputFormatDetector): the source has no HLSL technique block and no ShaderToy mainImage / void main entry point, or has both; pass --input-format fx or --input-format glsl. Library (ShaderConverter, kind AmbiguousInput): the source has both an HLSL technique block and a GLSL entry point and the name hint did not settle it; pass a name hint ending in .fx or .glsl, or call the format-specific entry point. A real error, never a reason to try another loader. InputFormatDetector, ShaderConverter
SD0006 ShaderToy/GLSL front-end conversion failed: a construct outside the supported single-pass image subset (e.g. mainSound / mainVR / mainCubemap, or a malformed mainImage signature). Located on the original .glsl, not the generated .fx. PipelineRunner, ShaderFiddle.Web
SD0007 Warning. A non-fatal ShaderToy/GLSL conversion adjustment (e.g. a local auto-renamed because it shadows a called function, or a dropped standalone void main() wrapper). Located on the original .glsl. PipelineRunner, ShaderFiddle.Web
SD0008 Warning. An #include resolved only because this host's file system ignores case: the spelling in the directive differs from the file's real name by case alone (#include "shared/macros.fxh" for a file named Shared/Macros.fxh). Android, Linux, and case-sensitive APFS do not ignore case, so the same shader fails there with SD0001. Match the on-disk spelling. Only the segments the directive itself spells are checked — the absolute prefix above them is your machine's own layout and never ships. Preprocessor
SD0009 Warning on every target when the managed preprocessed view of the technique list (issue #407) cannot be built (a directive or #if expression it does not model, such as __has_include(...), or a conditional on a compiler-predefined macro such as __HLSL_VERSION, __SHADER_TARGET_MAJOR or __spirv__; the other macros the pinned DXC defines, such as __GNUC__ or __llvm__, are undefined here as they are to mgfxc's preprocessor, and so is a name neither compiler defines, such as _XBOX, _DEBUG or __PSSL__): the compile then reads the techniques from the raw source, as before #407. Error on OpenGL (and the raylib converter) for the view that decides which SamplerState X : register(sN) declarations reserve a GL sampler register (issue #283) and which unit a legacy sampler X : register(sN) pins its texture to (issue #299; mgfxc decides both on the preprocessed source) could not be built, because a directive or #if expression is one ShadowDusk's managed preprocessor does not model (for example #if __has_include(...), or a computed #include MACRO). Raised only after DXC has accepted the same source, so a genuinely malformed shader still reports DXC's own diagnostic; reaching this code means ShadowDusk's preprocessor is the side at fault, and it refuses rather than allocate sampler registers on a guess. Carries the file and line of the offending directive. The same view, in its compiler-input form, is what the issue #308 legacy-sampler recovery compiles from (FxPreParser.ParsePreprocessed); there a view that cannot be built surfaces as SD0016, since the compile has already failed. FxMacroPreprocessor (via FxPreParser.CollectGlSamplerSlots / CollectReservedGlSamplerSlots / ParsePreprocessed / ParseTechniquesPreprocessed), CompilationPipeline, RaylibConverter, SkslConverter
SD0010 Effect source contains no techniques. CompilationPipeline
SD0011 Unrecognised value for a render-state key. RenderStateParser
SD0012 OpenGL: a GL uniform in the rewriter's register layout has no matching reflected effect parameter — the GLSL uniform layout and the reflection diverged. A uniform SPIRV-Cross renamed (a GLSL reserved word, noise → _noise; a run of underscores, my__val → my_val; a collision, _input_1) is mapped back by position through DXC's SPIR-V member names (issues #438, #440), with the single-cbuffer declaration-order bridge as the fallback, so this fires only when the GLSL uniform blocks pair with none of the SPIR-V constant buffers and the bridge cannot prove the mapping either. Any occurrence is a ShadowDusk bug; please report the shader shape. CompilationPipeline
SD0013 A pass compile <target> token does not resolve (after macro expansion) to a recognized shader profile — e.g. a typo (compile A …), an undefined *_SHADERMODEL macro (the #if OPENGL … #else … header was removed), or a profile-shaped-but-bogus literal (ps_9_9). Matches mgfxc/fxc's unrecognized compiler target. Fires on the GL/DX/Vulkan AND the FNA path. CompilationPipeline
SD0014 A pass compile <target> resolves to a profile whose stage prefix does not match the slot it is bound to — e.g. VertexShader = compile ps_3_0 … (a ps_* profile in a VertexShader slot) or PixelShader = compile vs_3_0 …. mgfxc/fxc reject this cross-stage binding. GL/DX/Vulkan path; the FNA path reports the same condition as SD0300 via ResolveFnaProfile. CompilationPipeline
SD0015 DirectX target only. A pass compile <target> resolves to a recognized profile that is nevertheless below MonoGame's DirectX_11 floor — e.g. compile ps_3_0 …, or the legacy #if OPENGL … #else … header that names SM3 in both arms. mgfxc rejects these with "Invalid profile 'vs_3_0'. Vertex shader 'VSMain' must be SM 4.0 level 9.1 or higher!"; ShadowDusk used to compile them, so the effect built here and then failed the consumer's real Content Pipeline build. Accepted set (measured against the pinned mgfxc): *_4_0_level_9_1, *_4_0_level_9_3, *_4_0, *_4_1, *_5_0 — note that *_4_0_level_9_0 and every SM6 profile are refused too. KNIFX container: the floor is KNI's own DirectX pipeline instead (KniDirectXProfile, measured with KNI's MGCB 4.2.9001 and 4.3.9001), which also accepts *_2_0 and *_3_0 by compiling them as *_4_0_level_9_1 / *_4_0_level_9_3 (recorded 2.0 / 3.0); everything else KNI refuses (*_2_a, ps_2_b, *_sw, SM1, *_4_0_level_9_0, SM6) is still SD0015, with a message naming KNI. Distinct from SD0013 (token is not a profile at all) and SD0014 (profile's stage does not match its slot). CompilationPipeline
SD0016 OpenGL, Vulkan and DirectX 12 (the targets that compile through DXC), and the raylib and SkSL converters (issue #327), which compile through the same DXC. The effect uses legacy D3D9 sampler syntax (sampler2D / sampler_state / tex2D) that the pre-parser's SM4 rewrite could not convert on the raw main file (it is declared or read in an #included file or through a macro, issue #308), the DXC compile failed, and the recovery that repeats the pre-parse on the preprocessed source could not be applied faithfully. Three reasons, each named in the message: legacy syntax is STILL in the compiler's input after the recovery (a shape the rewrite does not model, such as a sampler2D function parameter; the location is the construct's); a conditional tests a compiler-predefined macro (__HLSL_VERSION, __hlsl_dx_compiler, __SHADER_TARGET_*, …) whose value ShadowDusk's managed preprocessor cannot know, so the preprocessed text may not be the one DXC would compile (the location is the conditional's); or the preprocessed view cannot be built at all (the SD0009 reasons). Always appended AFTER the compiler's own verbatim diagnostics, never in place of them. Declaring the sampler and its tex2D call directly in the .fx file, or using Texture2D + SamplerState + .Sample, avoids it; DirectX 11 and FNA compile the legacy syntax natively. LegacySamplerRecovery (via CompilationPipeline.Run, RaylibConverter, SkslConverter)
SD0017 Warning, every MGFX and KNIFX target (OpenGL, DirectX 11, DirectX 12, Vulkan; .mgfx and .knifx), and the SkSL and raylib converters (issue #435), which report each uniform's declared default beside the converted shader. A global with an initializer (float R = 1;) would have shipped a default of zero, because ShadowDusk could not turn the initializer into its default value. ShadowDusk reads every declaration-scope numeric initializer off the preprocessed source and stores the value in the effect (DXC and vkd3d drop it, and mgfxc itself stores zeros on OpenGL), so this fires only for the initializers it cannot evaluate: a call to a function it does not model, a reference to a non-const global, a wrong component count, an array without a brace list, a multi-dimensional array, a declared type that disagrees with the parameter the compiler reflected, or a row_major non-square matrix on DirectX 11 or 12 that MonoGame's upload cannot fill: it writes C registers of R floats over the matrix's R one-per-row registers, so a wide one (more columns than rows) runs past the matrix and a tall one never reaches its rows at index C and beyond (a single tall one whose extra rows are zero, such as an affine float4x3, is kept), and an array of either is uploaded one element every C registers over a row_major stride of R, so its elements after the first land wrong. For those the message says why a runtime Set does not help either and suggests declaring the matrix column-major (or, for an array, separate parameters) instead of the Set advice below. The message names the variable and the reason, and the file/line/column point at the declared name. The compile still succeeds and the parameter works exactly as before: its default is zero until the game sets it. The same warning, naming <any global>, is raised when the preprocessed view that initializers are read from could not be built (a directive ShadowDusk's managed preprocessor does not model, see SD0009). Set the parameter by name at runtime, or simplify the initializer to a literal, a constructor of literals, or arithmetic over earlier const values. On the SkSL and raylib converters (ConvertedUniformDefaults) the same reasons apply to the reported DefaultValue (it is then null), plus two of their own: an initializer whose shape does not match the converted uniform, and a global with a default that no converted uniform could be paired with ("the converted shader declares no uniform ShadowDusk could pair with this global, so no default is reported for it"); the converted shader itself never carries a default, so the caller sets the uniform from DefaultValue.
SD0018 KNIFX container only. Internal: a sampler record's texture names no effect parameter, so the texture could not be bound. In KNIFX a record legally binds no parameter (-1) only for a legacy sampler that binds no texture (sampler s0;), as KNI's own pipeline writes it; any other unbound record is a reflection/parameter-table mismatch, a ShadowDusk bug, refused rather than shipped as "no texture". KnifxWriter raises the same code for a sampler record whose parameter index is neither -1 nor one of the effect's parameters. CompilationPipeline, KnifxWriter
SD0020 Constant-buffer size exceeds the MGFX int16 maximum. MgfxWriter
SD0021 Shader index exceeds the MGFX int16 maximum. MgfxWriter
SD0022 A count/index serialized as a single byte in the .mgfx shader record is outside 0–255 (samplers, constant-buffer indices, vertex attributes, sampler parameter index). MgfxWriter
SD0023 CompilerOptions.MgfxVersion is outside the MGFX header's byte range (0–255). CompilationPipeline
SD0024 A sampler_state member has an unparseable value for a recognized key (MinFilter/MagFilter/MipFilter/Filter, AddressU/V/W, BorderColor, MaxAnisotropy, MaxMipLevel, MipLodBias). MgfxSamplerStateResolver
SD0025 The Vulkan target was requested together with the KNIFX container (KNI ships no Vulkan platform). CompilationPipeline
SD0026 A shader declares more than one constant buffer for a single stage on the Vulkan target, which the format does not support — merge the globals into one cbuffer. CompilationPipeline
SD0027 The DirectX12 target was requested together with the KNIFX container (KNI ships no DX12 platform). CompilationPipeline
SD0028 Vulkan target: two distinct textures are sampled through one shared sampler in the same live code path — both would land on one combined-image-sampler descriptor, leaving the second unbound at draw. Judged per compiled shader: a call in a function its entry point never reaches, on a line an inactive #if drops, or in the other branch of the same #if does not count. Located at the offending Sample call; give each texture its own SamplerState. (SD0213 is this condition's post-compile reflection backstop.) VulkanTextureSamplerBindingRewriter
SD0029 Warning (CLI only). An .xnb output was requested with no /Profile: and no --target-runtime, so the container holds a DirectX_11 (WindowsDX) effect, the CLI's mgfxc-parity default. That file is correct for a WindowsDX game, but a MonoGame DesktopGL / Android / iOS / macOS game rejects it at Content.Load<Effect> with "This MGFX effect was built for a different platform!" and KNI with "Effect profile 'DirectX_11' is not compatible with the graphics backend 'OpenGL'" — neither names the profile or this tool, so the warning does. Never an error and never a required flag: name the profile your game targets (e.g. /Profile:OpenGL) and it goes away. PipelineRunner
SD0030 KnifxWriterOptions.Version is not a KNIFX version ShadowDusk writes (valid: 11, 12). Unreachable from the CLI or a CapabilityProfile; guards direct KnifxWriter callers. KnifxWriter
SD0100 SPIRV-Cross SPIR-V→GLSL transpilation failed (includes a SPIR-V blob whose byte length is not a multiple of 4). SpirvCrossGlslTranspiler
SD0101 Pure-managed reflection failed (DXBC RdefReader, SpirvReflector). RdefReader, SpirvReflector
SD0102 Native DXIL reflection (ID3D12ShaderReflection) failed. DxilReflectionExtractor
SD0103 SPIRV-Cross cannot run as ShadowDusk's pinned build, so the SPIR-V to GLSL stage (OpenGL) is refused rather than handed to a different SPIRV-Cross (issue #350). Raised when the native (spirv-cross.dll / libspirv-cross.so / libspirv-cross.dylib from Silk.NET.SPIRV.Cross.Native 2.23.0) is not found beside the ShadowDusk assemblies, in the application directory or in the host's native search directories (it is never loaded by bare name from PATH, LD_LIBRARY_PATH or DYLD_LIBRARY_PATH); when the files found there are present only as a different build (each candidate's SHA-256 is checked against the pin for the process RID before it is loaded; the message names each rejected file and its hash; the usual cause is another package raising Silk.NET.SPIRV.Cross.Native above 2.23.0, and the fix is to pin it to 2.23.0); when the pinned file cannot be loaded into the process; on macOS, when dyld mapped a different library than the file ShadowDusk loaded (DYLD_LIBRARY_PATH is searched by leaf name ahead of any absolute path); on Android, when the APK carries no libspirv-cross.so, or the one the linker mapped does not carry the pinned GNU build id for its ABI (read from the MAPPED image, since the APK holds no separate file; another package bundling its own copy is the case this catches; an ABI ShadowDusk ships no SPIRV-Cross for is refused the same way); or on an OS ShadowDusk ships no SPIRV-Cross for. The build-time counterpart of the different-build case is SD0226. The message names the searched directories. SpvcLoader via SpirvCrossGlslTranspiler
SD0104 Warning (Vulkan, DirectX 12; on OpenGL the same case is SD0210). A vertex-input semantic is not one ShadowDusk recognizes, so its attribute defaulted to VertexElementUsage.TextureCoordinate with the trailing numeric index. The value is deliberately unchanged — real mgfxc defaults exactly the same way, and it also prints a warning when it defaults, so a drop-in replacement must warn rather than reject (bug-hunt 2026-07-27 N5). Matters because a typo (TEXCORD0 for TEXCOORD0) silently mints a phantom TextureCoordinate attribute that MonoGame's VertexInputLayout then demands from the vertex declaration; the only symptom is a failed draw with no reference back to the shader. Raised on the Vulkan (SPIR-V) and DirectX12 (DXIL) attribute-table paths, the two targets that write this table. VertexSemanticMapper via SpirvVertexInputReflector, DxilVertexInputReflector
SD0200 Metal target not yet supported. CompilationPipeline
SD0201 A capability-profile shader feature (e.g. vertex texture fetch, texture arrays) has no shipping runtime support yet and cannot be enabled. Reserved for a future runtime proven to consume it. ShaderFeatureSupport
SD0210 Two historical meanings (known shared code): (a) the d3dcompiler_47 oracle backend refused the request (requires Windows, or a ProfileOverride it never serves); (b) the MonoGame GLSL rewriter could not lower a construct to MonoGame's GL dialect — incl. int/bool/mat3/struct uniform-block members, a whole-array uniform use, any surviving reference to a rewritten uniform block, a vertex-input semantic the shared VertexSemanticMapper does not recognize (mgfxc's OpenGL compile refuses one too, fxc X4502; there is no TextureCoordinate fallback on OpenGL), an int/uint/matrix vertex input, or a matrix interpolant that is not at a TEXCOORD semantic, overlaps another interpolant's registers, or is written by a vertex shader with a return statement; a matrix interpolant the entry point's scanned signature does not declare (e.g. a semantic on a struct-typed member whose struct holds a matrix, or a type defined twice at file scope), or a float1xN vertex input (fxc gives it N attributes); PSIZE0 beside POINTSIZE0 as vertex inputs; a nointerpolation or array matrix interpolant. Since issue #425 (b) also covers an explicit packoffset that puts a vector mid-register (float3 b : packoffset(c0.y)) on OpenGL: the std140 SPIR-V fails DXC's own validator ("must follow standard uniform buffer layout rules"), which is reported as SD0210 with DXC's text kept verbatim, instead of DXC's "file a bug report" X0000. D3DCompilerShaderCompiler, CompilationPipeline, DxcDiagnosticReformatter
SD0211 vkd3d-shader cannot run as ShadowDusk's pinned build (vkd3d 2.1), so the DirectX 11 / FNA compile is refused rather than handed to a different vkd3d (issue #350). Raised when the native (libvkd3d-shader-1.dll / libvkd3d-shader.so.1 / libvkd3d-shader.1.dylib, shipped by ShadowDusk.HLSL for win-x64, linux-x64, osx-x64 and osx-arm64) is not found beside the ShadowDusk assemblies, in the application directory, in the host's native search directories or (a repo checkout) under tools/vkd3d/ (run tools/restore.ps1 there); it is never loaded by bare name from PATH, LD_LIBRARY_PATH or DYLD_LIBRARY_PATH (Wine ships a libvkd3d-shader). Also raised when the files found are present only as a different build (each candidate's SHA-256 is checked against the tools/restore.* pin for the process RID before it is loaded; the message names each rejected file and its hash), when the pinned file cannot be loaded, on macOS when dyld mapped a different library than the file ShadowDusk loaded, and on any RID or OS ShadowDusk ships no vkd3d for (Android, win-arm64, linux-arm64, ...). The message names the searched directories. Vkd3dLoader via Vkd3dShaderCompiler
SD0212 vkd3d-shader compile failed and emitted no diagnostic text at all (unparseable non-empty text passes through verbatim as X0000). Vkd3dCompileContract
SD0213 Vulkan target: reflection shows two distinct textures co-located onto a single combined-image-sampler binding — the second texture would silently sample the first's data on DesktopVK. The post-compile backstop of SD0028, for shared-sampler shapes the source-level scan cannot see. Give each texture its own SamplerState (or explicit register). CompilationPipeline
SD0214 Retired (issue #478). Formerly warned that DirectX12 DXIL compiled on a non-Windows host was unsigned. Every host now writes the DXIL container hash (the same bytes dxil.dll writes), so the warning is never emitted. The code stays reserved. DxcShaderCompiler
SD0215 Retired (Phase 51 A7). Rejected sampler registers that were not contiguous from s0, because the GL record was named ps_s{sampler.BindSlot}. The record index is now the combined sampler's declaration position, so bind slots are never consulted for GL naming and register(s3) compiles correctly. Do not reuse this number. —
SD0216 Retired (Phase 51 A7). Rejected the shared-SamplerState shape (N textures through one sampler) because the GL sampler table was keyed on the reflected samplers and could not name every ps_s{k} the GLSL declared. The table is now keyed on the (texture, sampler) pairs, so the shape compiles as mgfxc does. Do not reuse this number. —
SD0217 OpenGL target: the combined-sampler declaration order the GL sampler table must mirror could not be determined from the SPIR-V — an input shape SpirvCombinedSamplerPairs does not model (an already-combined sampled image at module scope; an ARRAY of textures or samplers, Texture2D Tex[N] / SamplerState S[N], named as such in the message since issue #324, a shape real mgfxc /Profile:OpenGL fails on too with Sequence contains no matching element; a struct of separate samplers; a sampling operand that does not resolve to a module-level declaration), or an internal mismatch between the derived pair count and the number of sampler uniforms the emitted GLSL declares. Never raised by ordinary HLSL. On the real-slangc .slang route an ARRAY of combined samplers (Sampler2D Comb[N], SamplerCube Sky[N], issue #356) gets the same code: slangc lowers it to a texture array plus a sampler array, SPIRV-Cross cannot remap the sampler array (its SD0100), and that failure is reported as SD0217 at the author's declaration, naming the array and the fix (declare each element as its own combined sampler), with SPIRV-Cross's own message kept verbatim at the end and in RawDiagnostics. Only when the author's source declares that combined sampler as an array: an author-written SamplerState S[N], including one named like the lowering (SamplerState My_sampler_0[2]), stays SPIRV-Cross's SD0100. SpirvCombinedSamplerPairs, CompilationPipeline; SlangCompiler (the combined-sampler array)
SD0218 Vulkan target: the shader calls an HLSL Shader Model 6 wave/quad intrinsic (WaveActiveSum, QuadReadAcrossX, ..., named in the message when identifiable). Not supported: MonoGame's DesktopVK runtime creates a Vulkan 1.0 instance with no subgroup support, and the SPIR-V 1.3 / GroupNonUniform module these need was measured out of spec there by the Khronos validation layer (issue #229). The .fx route keeps DXC's location and appends DXC's own message verbatim; the real-slangc .slang route reports the construct's source line before spawning slangc. Remove the intrinsic from the Vulkan build (e.g. #if !VULKAN) or build for DirectX12. DxcShaderCompiler, SlangCompiler, WaveQuadIntrinsics
SD0219 DXC cannot run as ShadowDusk's own pinned build, so the compile is refused rather than handed to a different DXC. Raised first, before any native is touched, when the process bound a Vortice.Dxc other than 3.3.4 (every DXC-backed request fails): another release ships a different DXC and a binary-incompatible managed API (3.8.3, which Evergine.DirectX12 pulls in, failed every DXC call with MissingMethodException even with the pinned natives in place, and on macOS and Android that used to be the only symptom); the message gives the fix (pin Vortice.Dxc to 3.3.4), and the build-time counterpart is SD0220. Raised when no pinned build is found (every DXC-backed request fails): the natives (dxil.dll + dxcompiler.dll on Windows, libdxcompiler.so on Linux, libdxcompiler.dylib on macOS) are missing beside the ShadowDusk/Vortice assemblies, the app and the host's native search directories, cannot be loaded into this process (a pinned-version file of the other architecture is skipped and only reported if nothing loads), or are present only as a different build (checked before loading by the stamped identity: the PE file version plus the ProductVersion build tag, 1.7.2212.40 (e043f4a12), on Windows, the ELF GNU build id on Linux, the Mach-O LC_UUID on macOS; the message names each rejected file and what it is, the pinned build, and the Vortice.Dxc version the process resolved; the usual cause is another package raising Vortice.Dxc above 3.3.4, which NuGet reports as NU1608 at restore, and the fix is to pin Vortice.Dxc to 3.3.4), or, on macOS, when dyld mapped a different build than the file ShadowDusk loaded (dyld searches DYLD_LIBRARY_PATH by leaf name ahead of any absolute path); or, on Android, when the libdxcompiler.so mapped from the APK does not carry the pinned GNU build id for its ABI (read from the mapped image, since the APK holds no separate file; another package bundling its own copy is the case this catches; an ABI ShadowDusk ships no DXC for is refused the same way); or when the OS has no bundled DXC at all (Android without the APK's libdxcompiler.so, iOS, Mac Catalyst, FreeBSD). Also raised for validated-DXIL compiles only (DirectX 12) when a different dxil.dll was loaded into the process before ShadowDusk's (DXC binds its validator and signer to the module already loaded under that name; a copy of the pinned file is accepted) or, on macOS, when any libdxil image is loaded (our DXC build ships none, so dyld found a foreign one through DYLD_LIBRARY_PATH, the working directory, or /usr/local/lib). DirectX 11 and FNA never use DXC, and OpenGL, Vulkan and preprocessing never call the validator, so those keep compiling in the validator case. The message names the paths. DxcLoader via DxcShaderCompiler, DxilReflectionExtractor
SD0220 Build warning, raised in the consumer's own build (by buildTransitive/ShadowDusk.HLSL.targets, which ShadowDusk.HLSL ships and which therefore also runs for ShadowDusk.Compiler and ShadowDusk.ContentPipeline consumers): the project resolves a Vortice.Dxc other than 3.3.4, so every DirectX 12, OpenGL and Vulkan compile will fail at runtime with SD0219. The usual cause is another package raising it (Evergine.DirectX12 pulls 3.8.3; NuGet's NU1608 in the same build names the package). Fix: pin <PackageReference Include="Vortice.Dxc" Version="3.3.4" /> (or the matching PackageVersion under central package management); if a package needs the newer release, the DXC-backed targets cannot run in that application, so compile those shaders at build time. A warning, never an error: DirectX 11 and FNA do not use DXC and keep building. Suppress with <NoWarn>$(NoWarn);SD0220</NoWarn>. buildTransitive/ShadowDusk.HLSL.targets
SD0221 Vulkan target: a texture or sampler is declared as an ARRAY (Texture2D Tex[N], SamplerState S[N]; the name, element count and declaration are in the message, located at the declaration). MonoGame's Vulkan effect format binds one texture per descriptor slot and names it by one effect parameter, so an array of resources has no representation: real mgfxc 3.8.5 (/Profile:Vulkan) reflects Texture2D Tex[N] as no parameter, no sampler record and no descriptor binding at all (measured 2026-10-02 for N = 1, 2 and 4, with and without an explicit register; the SPIR-V still samples the array), and loaded into real MonoGame 3.8.5 DesktopVK that effect has no Tex parameter and draws nothing (validation/VsDrivenVulkan -- texarr-reference); it refuses a sampler array on every profile in its own parser (Unexpected token '[' found). ShadowDusk used to drop the array silently in its SPIR-V reflection (issue #324: Texture2D Tex[2] compiled to an effect whose only parameter was the sampler); it now refuses the shape. Declare each element separately and sample each by name, or keep the array out of the Vulkan build with #if !VULKAN. On the real-slangc .slang route a Sampler2D T[N] is the same shape and gets the same code, located at the Slang declaration. ResourceArrayDiagnostics via CompilationPipeline
SD0222 Warning. DirectX 12 target: a TEXTURE is declared as an ARRAY of two or more elements (Texture2D Tex[N]; located at the declaration). The output is not changed: the effect reflects one parameter bound to the first slot, exactly the table real mgfxc 3.8.5 (/Profile:DirectX_12) writes (measured 2026-10-02 for N = 1, 2 and 4, with and without an explicit register; header maxTextureSlot 0). But elements beyond [0] cannot be set through Effect.Parameters, and because the shader header sizes the descriptor range for one texture they read as zero in real MonoGame 3.8.5 WindowsDX12 even with GraphicsDevice.Textures[i] set (measured by validation/VsDrivenDx12 -- texarr, where mgfxc's own build does the same). Declare each element separately and sample each by name if every element must be read. Not raised for a 1-element array, which is one texture and behaves as one. A SAMPLER array is SD0224 (an error) instead. DirectX 11 raises nothing for a texture array (issue #339): its table is mgfxc's too (one parameter, one record at the array's base slot) and, unlike WindowsDX12, real MonoGame WindowsDX reads the other elements through GraphicsDevice.Textures[i] (measured by validation/VsDrivenDx -- texarr). ResourceArrayDiagnostics via CompilationPipeline
SD0223 A SPIR-V compile with debug information (Debug, so -Zi, on the OpenGL or Vulkan target) is refused because DXC's own second load of its library would not be ShadowDusk's pinned build (issue #332). DXC's SPIR-V emitter reads the source for OpSource through DxcDllSupport::Initialize, a load of libdxcompiler by LEAF name (dlopen("libdxcompiler.so" / "libdxcompiler.dylib"), LoadLibrary("dxcompiler.dll")) made from inside every -Zi SPIR-V compile; whatever the dynamic linker answers is loaded and initialized inside the compile. DxcLeafNameLookup asks the linker, without loading anything (RTLD_NOLOAD; GetModuleHandleW), what that answer is: the pinned image (Windows; macOS 14+, which matches the leaf to the loaded image's @rpath/libdxcompiler.dylib install name), nothing (glibc's normal case: DXC's load fails and the emitter uses the in-memory source), or a different library: a libdxcompiler.so on LD_LIBRARY_PATH (the Vulkan SDK's setup-env.sh puts one there), a libdxcompiler.dylib where dyld on macOS 12/13 searches (DYLD_LIBRARY_PATH, the working directory, DYLD_FALLBACK_LIBRARY_PATH), or a dxcompiler.dll another component loaded before ShadowDusk's first use (Windows returns the first module of that name). Only the last case raises this code, and only for the compiles that make the load; a byte copy of the pinned build is the same compiler and is accepted. The message names the library the linker would hand DXC, the pinned one, and the fix (remove it from the search path, or compile without debug information). Release compiles, DXIL (DirectX 12) debug compiles, DirectX 11 and FNA never make the load and are unaffected. DxcLeafNameLookup via DxcShaderCompiler.CompileCore
SD0224 DirectX 11 and DirectX 12 targets: a sampler is declared as an ARRAY (SamplerState S[N], any N, [] included; the name, element count and declaration are in the message, located at the declaration). Real mgfxc (3.8.4.1 and 3.8.5, measured 2026-10-02) refuses an array of samplers on EVERY profile in its own effect parser before any shader compiles (file(line,col) : Unexpected token '[' found. Expected Semicolon, Comma, or CloseParenthesis.), so no reference output exists for the shape, and MonoGame's effect format has no place for it (a sampler record carries one sampler slot keyed to one texture slot and names no element). ShadowDusk used to compile it anyway (issue #340): the records are keyed on the TEXTURE bindings, so a sampler element never gets a record of its own (DirectX 11 gave Tex[2] + S[2] one record per element and, before issue #339, parameters Tex[0]/Tex[1]; DirectX 12 gave it one record for slot 0). Measured as evidence before refusing: the pre-fix effects of texture-arrays/SamplerArray2.fx (two textures through Samplers[2]) loaded into real MonoGame WindowsDX and WindowsDX12 and drew with both textures sampled (two records, t0/s0 and t1/s1), so the refusal is parity with the reference compiler, which builds no effect for the shape at all, not an engine failure. Detected from reflection (SamplerReflection.ArrayLength: the collapsed SM5 records on DirectX 11, DXIL's BindCount on DirectX 12) with the declaration text as the fallback for a 1-element array on DirectX 12 (DXIL reports BindCount 1 for it). Declare each sampler separately and sample through each by name. Vulkan refuses the same shape as SD0221; OpenGL cannot lower it (SD0100, SPIRV-Cross); FNA (fx_2_0, reference fxc) is not affected. On the real-slangc .slang route an author-written SamplerState S[N] gets the same code, relocated to the author's Slang line; slangc's own lowering of a combined-sampler ARRAY (Sampler2D T[N] becomes a texture array plus SamplerState T_sampler_0[N]) is exempt, because that sampler array is one author resource lowered, not the shape mgfxc's parser refuses: the texture half carries the array diagnostics and the table is the hand-written Texture2D T[N]; SamplerState S; one (one T parameter, one record at slot 0, on DirectX 11 and 12). ResourceArrayDiagnostics via CompilationPipeline; SlangCompiler (relocation, the combined-sampler exemption)
SD0225 Internal: a SPIR-V compile with debug information (Debug, OpenGL or Vulkan) returned a module whose instruction stream ShadowDusk cannot walk, so the OpSource text DXC may have read from files on the host's disk cannot be removed (issue #343: DXC fills each OpSource by reading the file it names wherever its leaf-name self-load succeeds; DxcDebugSpirvSource drops that text so debug output depends only on the compiled source). Refused rather than shipped. A ShadowDusk bug if ever seen; compile without debug information meanwhile. DxcDebugSpirvSource via DxcShaderCompiler, the browser DXC backend
SD0226 Build warning, raised in the consumer's own build (by buildTransitive/ShadowDusk.GLSL.targets, which ShadowDusk.GLSL ships and which therefore also runs for ShadowDusk.Compiler and ShadowDusk.ContentPipeline consumers): the project resolves a Silk.NET.SPIRV.Cross.Native other than 2.23.0, the release whose SPIRV-Cross natives ShadowDusk pins by SHA-256, so every OpenGL compile (and raylib / SkSL conversion) will fail at runtime with SD0103. The usual cause is a Silk.NET package or a direct reference moving it (issue #350). Fix: pin <PackageReference Include="Silk.NET.SPIRV.Cross.Native" Version="2.23.0" /> (or the matching PackageVersion under central package management). A warning, never an error: DirectX 11, DirectX 12, Vulkan and FNA do not use SPIRV-Cross and keep building. Suppress with <NoWarn>$(NoWarn);SD0226</NoWarn>. buildTransitive/ShadowDusk.GLSL.targets
SD0227 OpenGL, DirectX 11, DirectX 12 and Vulkan targets: two LEGACY samplers that one compiled shader reads are bound to the same explicit register (sampler2D A : register(s0); sampler2D B : register(s0);, bare or with a sampler_state block, also when both name one texture). fxc refuses this, and so does mgfxc 3.8.4.1 on OpenGL and DirectX_11 (X4500: overlapping register semantics not yet implemented 's0', measured 2026-10-03); the SM4 rewrite drops the clause, so ShadowDusk used to compile it and give the second sampler the next unit. Read off the preprocessed source (a register in an inactive #if branch does not count) and only for samplers the compiled stage reflects, like fxc: a second declaration nothing reads compiles, as in mgfxc, and so does a legacy sampler sharing its register number with a modern SamplerState, a Texture2D : register(tN) or a constant register(cN). Located at the second declaration and naming both samplers. FNA is refused by vkd3d itself (E5015). Also DirectX 11 only: a legacy sampler's register beside a MODERN SamplerState S : register(sN) on the same N that the shader reads (fxc X4500 at the modern declaration); vkd3d's own E5015 text is kept in RawDiagnostics. CompilationPipeline
SD0228 Vulkan target: a texture or sampler reached DXC without an explicit register and was given a SPIR-V binding below 32 (every such resource is named, with its kind and binding; the error sits at the first one the source declares literally, line 0 when none is). A Vulkan resource's slot is its binding minus 32: -fvk-t-shift 32 all / -fvk-s-shift 32 all put register(tN) at binding 32 + N, mgfxc 3.8.5 writes the slot as binding - 32, and MonoGame's DesktopVK descriptor writer reads a descriptor's image from textures[binding - 32], so a binding below 32 has no slot the runtime can bind. ShadowDusk's Vulkan binding rewrite pins every texture and sampler declaration it recognises (one Texture*/SamplerState/sampler per declaration, with or without a template argument or register) before compiling; this is one it does not model, such as two names in one declaration (Texture2D A, B;). Before refusing, the compile is retried once from the macro-expanded preprocessed source (a declaration that comes out of a macro, #define DECL_TEX(x) Texture2D x##Tex;, is literal there and gets its register); the code is raised only when that retry still leaves a resource below binding 32, and it is then the retry's error, naming only what the retry could not pin (a macro-declared resource the retry pinned is not named), located through the expanded text's #line map, so at the macro invocation when the declaration comes out of one. mgfxc writes the same shape as slot 224 with no descriptor binding (measured 2026-10-28). Declare the resource in its own statement with an explicit register, or keep it out of the Vulkan build with #if !VULKAN. Arrays of textures or samplers are SD0221 instead, and buffers (Buffer<T>, structured and byte-address buffers) SD0233. VulkanResourceSlots via CompilationPipeline
SD0229 Vulkan target: a texture, sampler or constant buffer is in a descriptor set MonoGame's DesktopVK does not bind for its stage (it binds a vertex shader's resources from set 0 and a pixel shader's from set 1 only; the resource, its set and the expected set are in the message, located at the declaration when it can be found). An explicit register space (register(t1, space0)) is a Vulkan descriptor set; ShadowDusk drops , spaceN from every t/s/b register clause it can see on the Vulkan target (mgfxc 3.8.5 keeps it, and its build of register(t1, space0) in a pixel shader draws (0,0,0,0) in real DesktopVK, measured 2026-10-28), and a space behind a macro is dropped by the retry from the preprocessed source. Raised when a resource still lands outside its stage's set: an explicit Vulkan binding attribute ([[vk::binding(N, set)]]) names the set directly, and ShadowDusk does not rewrite it. Remove the attribute or the , spaceN (ShadowDusk assigns every Vulkan binding itself). VulkanResourceSlots via CompilationPipeline
SD0230 Warning, DirectX 11 only: a compiled shader's textures could not be checked against, or put on, the tN slots fxc (and so mgfxc) gives them. fxc gives a LEGACY sampler's texture (sampler2D A;, a sampler_state block, read with tex2D) the slot of its first read in evaluation order, ahead of every modern resource without a register and around every explicit t register; ShadowDusk compiles the SM4 rewrite, whose backend numbers the textures in declaration order, reads the evaluation order from the preprocessed source, and re-pins the textures with explicit registers when the two differ. This warning means one of those steps was not possible, and the message says which: the order could depend on which reads fxc keeps once it folds the conditions it can evaluate (the check follows straight-line evaluation order, drops a read after an unconditional return/break/continue and numbers a switch's default arm last, as fxc does, but never evaluates a condition: a read under an if/else, in a switch arm, in a loop that is not certainly entered, in a later loop iteration, or after a return/break/continue that may not run may or may not be kept, and when that could change the order the check warns. So some of these warnings are orders fxc would in fact keep, typically a texture first read under a uniform or input condition such as if (k > 0) and read again after another texture; a shader whose every texture is first read unconditionally avoids it), an overloaded function, a legacy texture passed or assigned as a value (a legacy sampler passed to a function's sampler2D parameter is followed: the rewrite turns the parameter into Texture2D s_SDTexture, SamplerState s and the check reads through it, issue #443; through a function the rewrite leaves verbatim, because its name appears in a macro line or another use of it or of the sampler cannot be followed, the read is followed only when the sampler passed is one the main file's rewrite knows, and warns otherwise), a texture the shader binds whose read was not found, a read in a for increment, a statement (or for init clause) that discards the value of a call that reads (fxc DROPS tex2D(B, uv);, in parentheses, a block or a void helper, float4(tex2D(B, uv)); and Tb.Sample(SB, uv); before it numbers, but keeps tex2D(B, uv).r;, * 2, a cast, clip(...) and a user function's call; which calls it drops is not modelled, so every bare call that reads warns, max(tex2D(B, uv), 0); included, other than clip, sincos and a user function's), a read or user-function call in a global initializer (fxc numbers static float4 G = tex2D(B, uv); before the entry point's reads, even when nothing uses G), a function defined inside a struct, class, interface or namespace (a struct method, N::F), a legacy sampler's texture the shader also uses directly, through a method of its own (Tb.GetDimensions, Tb.Load, even Tb.Sample) or as a value anywhere, a global initializer included (static float4 G = Tb[int2(0, 0)];, static Texture2D Tc = Tb;, L(Tb); issue #447): fxc gives that use a texture record of its own, so mgfxc has A@t0 Tb@t1 Tb@t2 where ShadowDusk has one Tb record (this covers a sampler_state sampler declared in an #include or through a macro, which the backend compiles natively, and whose texture slots, since issue #447, are checked like any other legacy sampler's), two resources under one name; a resource declared through a macro, in a declarator list (Texture2D A, B;), as an array or with an annotation; an array of resources beside a legacy sampler; an unreadable resource table; a preprocessed view that cannot be built; or a pinned compile that failed or landed elsewhere. The effect still compiles, with the backend's declaration-order slots, so GraphicsDevice.Textures[N] and SpriteBatch's texture (slot 0) can reach a different texture than in mgfxc's build; textures set through their effect parameters are unaffected. Declaring the resources one per statement, or giving each an explicit register(tN), avoids most of these. CompilationPipeline (DxTextureSlotOrder, HlslReadOrder)
SD0231 Unassigned (never shipped). Briefly held the Vulkan read-write resource refusal on a development branch, renumbered to SD0233 before merge so it would not collide with SD0230. Do not reuse this number. —
SD0232 Vulkan target: a sampler has no texture on its descriptor binding (every such sampler is named, and so is each texture left with no sampler on ITS binding, the likely partner; located at the first sampler's declaration). MonoGame's DesktopVK binds a texture and the sampler it is sampled with as ONE combined descriptor, so ShadowDusk puts each pair on one register; a sampler it could not pair ships as a standalone SAMPLER descriptor beside a SAMPLED_IMAGE, a shape MGVK_UpdateDescriptors does not handle (an unhandled assert(0) branch and an uninitialised descriptor write) and that used to compile silently. Pairs are read from direct Tex.Sample(Sampler, ...) calls and followed through helper functions called with bare identifiers (H(B, U, uv), or a helper sampling a parameter texture through a global sampler), and an output that would still carry a standalone sampler is compiled once more from the preprocessed source (a sampler name from a macro, a token-pasted name, a pairing in an inactive #if all resolve there). Pairing is per compiled shader: only calls in functions the entry point reaches count, and a call on a line an inactive #if drops (read by the managed preprocessor with the compile's macros) pairs nothing. Raised when the pairing still cannot be seen: an expression argument (H(B, (U), uv)), a sampler in an array or struct, one chosen at runtime, an overloaded helper, or a texture already paired with another sampler that a helper samples through this one (a second sampler gets its own descriptor only on a direct call). Sample the texture through the sampler directly in the shader function. One texture sampled directly through two samplers is not this either: the second pairing gets an alias of the texture on its own combined descriptor (SD0235). A texture read only with Load (no sampler at all) is not this: it is a valid SAMPLED_IMAGE and gets mgfxc's own record. VulkanResourceSlots via CompilationPipeline, VulkanTextureSamplerBindingRewriter (pairing)
SD0233 Vulkan target: a storage resource (named with its kind, located at its declaration): a read-write texture (RWTexture*, a UAV), a texel buffer (Buffer<T>, RWBuffer<T>) or a storage buffer (StructuredBuffer, ByteAddressBuffer and their RW forms). MonoGame's Vulkan effect format has no descriptor for any of them (its layout binds uniform buffers and sampled textures only); mgfxc 3.8.5 writes a read-write texture with a slot that does not bind (measured: texSlot 225, no descriptor). A storage buffer used to compile silently as a uniform-buffer descriptor the runtime never fills, and a Buffer<T> compiled silently too. Detected from the SPIR-V: an OpTypeImage with Sampled = 2 or Dim Buffer, or a BufferBlock struct (DXC's default vulkan1.0 form of a storage buffer). Keep it out of the Vulkan build with #if !VULKAN. VulkanResourceSlots via CompilationPipeline
SD0234 Vulkan target: an identifier of the source ends in or contains _SDVkAlias, the suffix ShadowDusk reserves on Vulkan for the second descriptor it declares when one texture is sampled through two samplers (named, located at the first such identifier). An alias could collide with it, and its record would be bound to the wrong parameter. Rename the identifier. Other targets declare no aliases, so the name is an ordinary one there. CompilationPipeline
SD0235 Warning, Vulkan target: a texture is sampled through a second sampler in one compiled shader (the texture, the sampler and the shader are named, located at the call). MonoGame's DesktopVK binds a texture and a sampler as one combined descriptor, so ShadowDusk gives the pairing a second descriptor holding the same texture (an alias on its own register), bound to the texture's effect parameter. Set the texture through Effect.Parameters: SpriteBatch fills only the first texture slot, so a sprite texture read this way reaches only the first sampler. Raised only where the two samplers are used by the same shader: a texture read through a different sampler in each pass or stage needs no alias, and neither does one whose other sampler is only in an inactive #if branch. CompilationPipeline (from VulkanTextureSamplerBindingRewriter)
SD0236 OpenGL and Vulkan targets, and the raylib and SkSL converters (every DXC SPIR-V compile): the entry point is declared more than once in a shape ShadowDusk cannot compile safely. The pinned DXC's SPIR-V back end crashes the process (an uncatchable access violation inside dxcompiler) on an entry function that has a prototype, so the entry point's redundant prototypes (same return and parameter types and nothing the definition lacks, or an overload nothing calls) are blanked from DXC's input (each blanked character becomes as many spaces as its UTF-8 bytes, so DXC's columns do not move), and the effect compiles to the bytes it has without them. Every decision is made on what DXC's OWN preprocessor produces (-P, run with the compile's arguments; it never reaches the back end; skipped only when the source spells the entry's name at most once and defines no macro, so no directive spelling can hide one): a source whose preprocessed text declares the entry once (a prototype in a branch DXC does not compile included) reaches DXC exactly as written, and so does one DXC's preprocessor rejects (DXC reports it in its front end). A blanked range is accepted only when DXC's preprocessor, run on the source with it blanked, gives exactly the original tokens minus the prototype's (at most 32 ranges per prototype, 64 runs per compile), so a macro call beside the prototype is never removed with it, and a directive inside a multi-line prototype (#line, #if, #define) is kept. Refused instead: a call to the entry point between its prototype and its definition (without the prototype the call has no declaration); an overload prototype (different parameters, no definition) of an entry point the source calls; a prototype that says more than its definition (an attribute, a leading modifier such as inline, static or precise, a parameter's interpolation modifier or default value), which DXC may merge into the definition; a prototype no source range removes alone (a macro call writing it together with other code); and a declaration shape the reading does not model (a parenthesised declarator, float4 (PS)(...), or a second declarator, float4 A(), PS(...);) beside another declaration. On OpenGL the DXIL reflection companion, which has no fault, compiles a refused source as written, so DXC's own error from it (ambiguous entry point function, cannot find entry function) can be reported first, as in 0.22.1. In the browser, whose DXC module has no preprocess-only entry point, nothing is blanked: the source is compiled as written, and that DXC build's own rejection of a redeclared entry ("Entry points cannot share the same name"; it does not crash) is reported as SD0236 with DXC's file, line, column and text kept. mgfxc 3.8.4.1 compiles the call and overload shapes; reported at the call or the declaration, with the fix (move the definition above the call, write the prototype out on lines of its own, or remove it). DxcSpirvEntryRedeclarations (via DxcShaderCompiler), the browser DXC backend
SD0237 Vulkan target: a texture is sampled through a second sampler in one compiled shader (the alias SD0235 describes) and no texture slot of that shader's stage is left for the second descriptor (the texture, the sampler and the stage's slot count are named, located at the call). MonoGame's DesktopVK has 16 texture slots for a pixel shader and 8 for a vertex shader (MaxTextureSlots / MaxVertexTextureSlots in 3.8.5's MGG_Vulkan.cpp; the Vulkan shader header's texture-type table has 16 entries), so a descriptor past the last one has no slot the runtime can bind. An alias takes the lowest free slot above its texture's, else the lowest free slot below it, but never slot 0: SpriteBatch binds its sprite there over whatever the effect parameter set, so an alias on slot 0 would read the sprite. So the shader is refused when every slot but slot 0 is taken (a texture on the last slot read through two samplers, say, with every slot from 1 below it in use; the message says slots 1 to the last are all taken). Sample the texture through one sampler in that shader, or free a texture slot other than slot 0. VulkanTextureSamplerBindingRewriter
SD0238 Retired before release (never shipped). Briefly refused __TIMESTAMP__ in any DXC input (issue #444). Replaced by defining __TIMESTAMP__ to clang's own placeholder text on every DXC call, which keeps DXC's crashing built-in from ever expanding (pasted names included) and compiles what 0.22.1 compiled. Do not reuse this number. —
SD0239 DirectX 11 (vkd3d backend) and FNA targets: a cast to void ((void)tex2D(S, uv);, (void)x;, (void)0;, also inside an expression or written through a macro). It is not valid HLSL (fxc/mgfxc reject it with X3017), and the pinned vkd3d-shader crashes the whole process on it (an access violation inside vkd3d_shader_compile, measured on every such shape, issue #448), so it is refused before vkd3d sees the source, on the desktop and the browser host alike. Decided on the preprocessed view (managed preprocessor: a cast in an inactive #if branch or a comment is not one; one a macro writes is); a parameter list, F(void), is not a cast. Located at the ( of the first cast. Drop the cast. The d3dcompiler_47 backend is not guarded (it reports X3017 itself). Vkd3dInputGuard (via Vkd3dCompileContract.CheckSource)
SD0240 DirectX 11 (vkd3d backend) and FNA targets: a macro expands to itself where C stops the expansion at the repeated name: #define X X used in code or in an #if, #define F(x) F(x) called, two macros that name each other (#define A B / #define B A, or function-like), a macro naming the entry point after itself. fxc/mgfxc and DXC compile these per C, but the preprocessor of the pinned vkd3d-shader never returns on them (measured: one vkd3d_shader_compile call runs until killed, on FNA and on a ps_4_0 DirectX 11 copy alike, issue #449), so the compile is refused rather than hang the consumer's process. Decided by the managed preprocessor (the same hide-set expansion, in guard mode): reported when an object-like macro's name, or a function-like macro's name followed by a ( from the same expansion, comes back inside its own expansion. Not refused (vkd3d finishes on them, measured): a self-referential macro never used, tested only by #ifdef, used only in an inactive branch, a function-like name with no call after it (#define F(x) (x + F)), a name whose ( comes from after the expansion (ID(ID)(1)), nested calls (F(F(1))). Located at the line the name comes back on (the #if line inside a directive). Rename the macro or what it expands to. Not raised on the d3dcompiler_47 backend or the DXC targets. Vkd3dInputGuard (via Vkd3dCompileContract.CheckSource), FxMacroPreprocessor (guard mode)
SD0241 Every DXC compile (OpenGL, Vulkan, DirectX 12, and the raylib and SkSL converters; desktop and browser): an active #pragma pack_matrix (or _Pragma("pack_matrix(...)")) whose argument, after macro expansion, is not (row_major) or (column_major): bogus, ROW_MAJOR, (), a number, two arguments, an unclosed or missing parenthesis, a macro that expands to anything else. DXC rejects every one of these as an error (measured, sequentially, on DirectX 12, OpenGL and Vulkan), with a diagnostic whose expected-token text is missing ("invalid argument; expected or 'disable'"), and the pinned DXC sometimes crashes the process while reporting it: under parallel load on DirectX 12 (8 of 200 runs, issue #452), and on one sequential OpenGL run with ROW_MAJOR. So it is refused before any DXC call, with DXC's severity (an error). Read on the managed preprocessor's view with the compile's -D macros defined first: a pragma in an inactive #if branch is not one, a valid argument may be followed by anything (DXC compiles pack_matrix(row_major) junk), and a source the managed preprocessor cannot read is left to DXC. Located at the argument. Write (row_major) or (column_major), or remove the line. DirectX 11 and FNA (vkd3d) are not affected. DxcPackMatrixGuard (via DxcShaderCompiler, the browser DXC backend), FxMacroPreprocessor (guard mode)
SD0300 FNA profile policy violation (SM4+/SM1 profile, or stage/profile prefix mismatch). CompilationPipeline.ResolveFnaProfile
SD0301 D3D9 CTAB reflection failed. CtabReader
SD0302 fx_2_0 effect validation failed at write time. Fx2EffectWriter
SD0303 FNA effect build failed. Includes a DX10-style texture object (Texture2D/Texture3D/TextureCube sampled through a SamplerState) at an SM2/SM3 profile: vkd3d folds the pair into one texture-typed S+T sampler that real FNA throws Unhandled sampler state! on when a pass that samples it is applied, and fxc /T fx_2_0 refuses the source too (issue #230). Reported at the sampling call, with DX9 advice for the shape: e.g. texture2D T; sampler2D S = sampler_state { Texture = <T>; }; and tex2D (tex2Dlod/tex2Dgrad for SampleLevel/SampleGrad; texture3D+tex3D, textureCUBE+texCUBE for those dimensions). Fx2EffectBuilder
SD0304 Retired (Phase 39). Guarded "FNA unavailable on WASM" back when the browser host had no DXBC path. The vkd3d-shader WASM build removed the condition, so the guard no longer exists. Do not reuse this number. —
SD0305 MojoShader-compatibility bytecode patch failed. D3d9BytecodePatcher
SD0400 Warning. A gradient op (dFdx/dFdy/fwidth) sits inside a loop with a divergent exit (conditional break/discard) in the emitted GL fragment source. ANGLE Direct3D11 (WebGL in every Windows browser) silently evaluates such derivatives to 0.0; fxc warns X3553 and force-unrolls the same HLSL (issue #141). GlslPortabilityAnalyzer
SD0401 Warning. A pass with no vertex shader whose pixel shader reads interpolants SpriteBatch's built-in SpriteEffect VS never writes (anything beyond COLOR0 → vFrontColor / TEXCOORD0 → vTexCoord0). Drawn with SpriteBatch on GL, the program link fails on strict drivers at the FIRST draw with the engine's generic exception. GlslPortabilityAnalyzer
SD0402 Warning. A loop shape outside GLSL ES 1.00 Appendix A in the emitted GL source (header-less for (;;), empty-increment for with the index advanced in the body, while, or a genuine do-while) — may fail to load on WebGL1 / KNI Reach (issue #138); desktop GL, WebGL2, and KNI HiDef are unaffected. GlslPortabilityAnalyzer
SD0403 Warning. A GLSL-1.30+/ES-3.00-only construct survived into the versionless emitted GL source (transpose, sinh-family, isnan/isinf, texelFetch, bit-cast builtins, switch, uint types/literals, integer shifts, the integer bitwise/modulo operators & | ^ ~ %, an array constructor float[](…), or a round/roundEven/trunc, non-square matrix or array constructor a lowering missed). Lenient desktop drivers accept it; strict front ends (macOS OpenGL, Mesa, WebGL1) reject it at Effect-load time, and MonoGame 3.8.6 DesktopGL4 aborts the process — the class behind issues #149, #163, #453 and #475. An HLSL array initializer is lowered by Rule 18 to per-element assignments, so the array-constructor check fires only for a shape that lowering does not model (an array of arrays, a count that differs from the declared size, a module-level array read by another module-level initializer). A non-square matrix (mat3x4 from a (float3x3) cast or a truncating mul(float3, float4x4), or a non-square matrix interpolant) is lowered to a zero-padded square matN by the rewrite's Rule 17 since issue #453, so it warns only for a shape that lowering does not model (a non-square struct member or function parameter, a matrix plus a scalar; see docs/glsl-uniform-naming.md). GlslPortabilityAnalyzer
SD0500 MGCB plugin: the ShaderProfile processor parameter names a profile ShadowDusk does not have (valid: DirectX_11, DirectX_12, OpenGL, Vulkan). Leave it empty to derive the target from the content project's /platform:. ShadowDuskEffectProcessor
SD0501 MGCB plugin: the content build's platform (/platform: in a .mgcb, -p in a Content Builder) names a platform ShadowDusk has no backend for (the consoles, Stadia, or a number with no name on the host's TargetPlatform). Fails the build rather than emitting a GL artifact that runtime cannot load. The message's supported list is built from MgcbPlatformMap, so it can never name the platform it refuses (on MonoGame 3.8.5 the old member-keyed map refused Web with a message listing Web as supported). ShadowDuskEffectProcessor
SD0502 MGCB plugin: invalid DxbcBackend processor parameter (only vkd3d, d3dcompiler). The plugin-side twin of the CLI's X0006. ShadowDuskEffectProcessor
SD0600 Slang frontend: a Slang-only language feature (import, module, extension, associatedtype, interface, __generic, or a generic type-parameter constraint such as <T : IFoo> — named in the message) appeared in the source. ShadowDusk compiles the HLSL-compatible subset of Slang: the shader body goes through the same pipeline as every .fx, with nothing extra to install on any platform (the deliberate trade, owner direction 2026-08-13 — no Slang toolchain is shipped or invoked, so features with no HLSL meaning have nothing to lower to). Rewrite the construct in plain HLSL terms — or add the ShadowDusk.Slang package (Phase 66), which compiles real slangc-backed Slang instead of this HLSL-compatible subset. Subtler Slang-isms this courtesy scan misses fall through to DXC, whose own verbatim diagnostics apply. SlangFrontend
SD0602 Slang frontend: an entry point is [shader("...")] for a stage no supported consumer runtime can load (compute, mesh, the raytracing set, …). Stock MonoGame and KNI Effects hold exactly two stages — vertex and pixel (the Phase 58 measurement behind FX0014) — so this is a runtime limit, not a ShadowDusk gap, and it is rejected loudly by name rather than silently skipped. SlangEntryScanner
SD0603 Slang frontend: no [shader("vertex")] / [shader("fragment")] entry points found. Slang has no technique/pass concept, so the attributes are the only statement of intent ShadowDusk can synthesize the technique from. SlangEntryScanner
SD0604 Slang frontend: more than one entry point for the same stage. One .slang synthesizes one technique with at most one vertex and one pixel entry; split extra entries into separate files. SlangEntryScanner
SD0610 SkSL converter: the pass compiles a vertex shader (named in the message), or has no pixel shader. SkSL runtime effects have no vertex stage (a Skia platform limit); only pixel-only passes convert, and a vertex shader is refused rather than silently dropped. SkslConverter
SD0611 SkSL converter: the pixel shader reads an interpolant (named in the message) that an SkSL runtime effect cannot supply — runtime effects have no varyings at all; a pixel shader gets the coordinate plus uniforms. Any interpolant other than TEXCOORD0 and COLOR0 is refused by default (Gum's own hand-written SkSL port silently dropped its COLOR0 tint exactly this way); TreatVaryingsAsUniforms is the documented, warned-about opt-in that substitutes a per-draw in_var_<SEMANTIC> uniform. COLOR0 itself converts by default (see SD0614); it is refused here only when the shader reads it as something narrower than float4, because the synthesized uniform is a float4. SkslGlslMapper
SD0612 SkSL converter: a texture sample the converter cannot map to one .eval(): a sampling bias or any other extra argument, a sampler that is not one of the shader's own textures, or an unbalanced call. Sampling at a computed coordinate converts since issue #371 (child.eval((uv) * ShadowDusk_Resolution): HLSL coordinates are normalized, .eval() takes child pixels), and so does the interpolated TEXCOORD0 (child.eval(coord)); everything else is refused by name rather than guessed. SkslGlslMapper
SD0613 SkSL converter: a construct with no SkSL runtime-effect equivalent (named in the message): gl_* builtins, derivatives (dFdx/dFdy/fwidth), LOD/offset/fetch sampling, or a multi-render-target output. Refused rather than approximated. SkslGlslMapper
SD0614 Warning. SkSL converter: a uniform was synthesized that the consumer's draw code MUST set — ShadowDusk_Color (float4, the sprite's tint; stands in for COLOR0, SpriteBatch's vertex color, which every sprite shader reads; set it to the container tint, white when untinted; never leave it unset, SkiaSharp does not zero a runtime effect's uniform buffer, so an unset value is undefined), ShadowDusk_Resolution (float2, the pixel size of the element being drawn, which is also the size of the bound child textures; synthesized when the shader uses its UV arithmetically or samples at a computed coordinate) or a TreatVaryingsAsUniforms substitution (in_var_<SEMANTIC>). Every synthesized uniform is also listed in SkslConversion.SynthesizedUniforms. SkslGlslMapper
SD0615 SkSL converter: the effect has multiple techniques or passes. An SkSL runtime effect is a single fragment function, so converting one pass and dropping the rest would be a silent guess — split the effect instead. SkslConverter
SD0620 Real-slangc Slang route (ShadowDusk.Slang): this host cannot run the bundled slangc, and the message names why: the RID is not one of the four bundled (win-x64, linux-x64, osx-x64, osx-arm64; win-arm64 and linux-arm64 are deliberately not bundled, issues #227/#286), and the message names the host's RID and asks for an issue, or it is macOS older than 26 (the upstream macOS build's own minos). Checked only after the host-independent rejections (SD0602/SD0603/SD0624), so those report the same on every host. ShadowDusk.Compiler's built-in .slang subset frontend works everywhere if the source does not need genuine Slang-only features. A self-built slangc for older macOS is not planned; the message asks the consumer to open an issue if they need one. SlangCompiler, SlangToolPath
SD0621 Real-slangc Slang route: slangc was not found for this RID. SlangToolPath probed the app base directory, runtimes/<rid>/native/ under it, the host's native search directories, and a repository tools/slang/<rid>/ restore. A package consumer should never see this (the native rides inside the package); a repo/dev build that never ran tools/restore.sh/restore.ps1 does. SlangCompiler
SD0622 Real-slangc Slang route: slangc failed compiling one entry point (or, after every entry point compiled, failed its preprocess-only -E pass, which finds the registers the author wrote) and its stderr either did not match slangc's own error[E#####]:/warning[W#####]: diagnostic shape (an unanticipated failure — a native crash, an internal-compiler-error) or was empty, or the OS refused to start the process at all (the OS's own reason is the message; on Windows the launch runs with the thread's hard-error dialogs off, so a damaged or wrong-architecture slangc.exe fails at once instead of opening a modal "Unsupported 16-Bit Application" box). The complete stderr text (when any) is the message verbatim; never a generic sentence. When the exit code is a crash rather than a failure status (negative on Windows, an NTSTATUS such as 0xC0000005; 128 or more on Unix, a signal) and slangc printed no structured error, the message names the crash, the exit code and the one trigger known to produce it (issue #323: two same-named shader parameters in different namespaces, reported as SD0643 whenever a text ShadowDusk reads shows both), with slangc's own output (its warnings, or unstructured text) kept verbatim after it, never promoted to the failure. SlangCompiler, SlangDiagnosticReformatter
SD0623 Real-slangc Slang route: could not prepare slangc to run. Its compiler library must sit beside it (a partial restore names the missing file), it must be executable (SlangNativeCache sets the execute bit, or runs a cached copy it owns), and its directory must be writable (slangc writes a runtime cache file, slang-glsl-module.bin, into its own directory on first compile; SlangNativeCache falls back to a per-user cache copy). SlangCompiler, SlangNativeCache
SD0624 The source calls an HLSL Shader Model 6 wave/quad intrinsic (WaveActiveSum, QuadReadAcrossX, …, named in the message) targeting OpenGL, DirectX (DX11), or FNA, all architecturally capped below SM6 (OpenGL's fixed DXC SM5 profile, DX11's SM5 DXBC container, FNA's SM≤3 fx_2_0) and can never represent it. The .fx route relabels the compiler's own rejection (DXC's Vulkan 1.1 is required on OpenGL, vkd3d's Function "X" is not defined on DX11/FNA), keeping its line and column and appending its text; the real-slangc .slang route reports the construct's source line before spawning slangc. Both use one message. Build for DirectX12 instead (Vulkan rejects it too, as SD0218). DxcShaderCompiler, CompilationPipeline, SlangCompiler, WaveQuadIntrinsics
SD0625 Real-slangc Slang route: two entry points emit a global with the same name but different contents that cannot be renamed apart (a cbuffer, texture or sampler; the name is a reflected effect parameter). Struct, function and static collisions, which slangc's per-entry numbering does produce when two entries instantiate a generic differently, are renamed by the merge and never reach this code. Rename the parameter or split the entries into separate sources. SlangCompiler, SlangHlslMerger
SD0626 Real-slangc Slang route: the source is an HLSL Effect (.fx) file, not Slang. It spells a technique block, a VertexShader = compile pass state, or one of MonoGame's Macros.fxh entry macros (TECHNIQUE, DECLARE_TEXTURE, BEGIN_CONSTANTS). Real slangc cannot parse techniques or the legacy sampler type (measured against MonoGame v3.8.5's own effects: 0 of 66 entries compile). Compile .fx files through the .fx route (EffectCompiler, the CLI, the MGCB plugin). Checked before the entry scan, so it reports on every host. SlangCompiler, SlangEffectFrameworkGuard
SD0627 Real-slangc Slang route, FNA target: slangc's emission contains a texture construct the DX9 respelling does not model (named in the message, located at the Slang source line via slangc's #line directives): a texture or sampler passed as a function parameter, a subscript load T[...], SampleLevel/SampleGrad/Load/Gather, a non-2D texture, a Sample call with an offset argument or a non-global sampler expression, one SamplerState used with two textures, a sampler no T.Sample(S, uv) uses directly, or a non-zero register space. FNA's fx_2_0 binds textures through texture/sampler_state/tex2D, so the route respells slangc's Texture2D + SamplerState + T.Sample(S, uv) into exactly that (issue #230) and refuses anything else rather than guess. SlangCompiler, SlangFx2TextureRespeller
SD0628 Real-slangc Slang route (issue #292): slangc's output carries a texture/sampler register on a declaration that came from another file (an imported module or an __included file, which slangc -E of the entry source does not expand), and no preprocess pass ShadowDusk can run proves whether the author wrote it or slangc numbered it (slangc numbers an imported resource with no author register itself). ShadowDusk runs -E with the compile's macros over the file slangc's #line names and over the files imported or __included by quoted path, and trusts a file's text only when the file is a module (reached through quoted-path imports, or opening with a module/implementing declaration; an #included fragment's text depends on its includer's macros). This code means no trusted text decides: a file reached only by module name (import foo;) that has no module declaration, a register spelled through a macro no module defines, a declaration inside a namespace or block, modules that disagree, or a file the pass cannot open (slangc's own message is quoted). The browser's slangc has no file system, so there an import already fails the compile itself with slangc's own E00001, before this pass. Located at the declaration's file and line (at the entry source for a combined sampler's half, whose #line is slangc's core module). Declare the resource in the entry source, import its module by quoted path, or open the file with a module declaration. SlangCompiler, SlangcRegisterStripper
SD0629 Real-slangc Slang route: slangc's preprocess-only pass (slangc -E, which finds the texture/sampler registers the author wrote) exited 0 but printed nothing, or printed output that does not contain an entry point the compile just found. ShadowDusk will not read that as "the author wrote no register", which would silently move every author-registered texture to another slot. SlangCompiler
SD0630 raylib converter: the effect has more than one technique, or its technique more than one pass (the line and column point at the second one). A raylib shader is one program with no technique or pass concept, so converting one and dropping the rest would be a silent guess. Split the effect, one .fx per pass. RaylibConverter
SD0631 raylib converter: the pass compiles a vertex shader (named in the message, located at its compile profile), or has no pixel shader. The converter emits fragment shaders that run behind raylib's built-in vertex shader (LoadShaderFromMemory(null, fs)); raylib's vertex conventions are not mapped yet. RaylibConverter
SD0632 raylib converter: the pass sets render state (blend, depth, stencil, rasterizer; every assignment is named, located at the first). A raylib shader is GLSL text only and raylib sets that state from draw code (BeginBlendMode, ...), so it would be silently lost. RaylibConverter
SD0633 raylib converter: the pixel shader reads an interpolant raylib's built-in vertex shader cannot supply, or declares one with a different type or interpolation mode. raylib supplies exactly TEXCOORD0 as fragTexCoord (vec2) and COLOR0 as fragColor (vec4). RaylibGlslMapper
SD0634 raylib converter: a construct whose value depends on the render target's Y orientation (SV_Position/gl_FragCoord, ddy/dFdy, other gl_* builtins; MonoGame and raylib flip render targets in opposite directions), or an output other than one float4 (multiple render targets, depth output). RaylibGlslMapper
SD0635 raylib converter: a name collision or a sampler raylib cannot bind: an identifier spelled like a raylib-reserved name (colDiffuse, mvp, texture0, ...), a non-2D texture, an extra texture read through two samplers, a texture whose name would be a GLSL keyword or builtin, or a uniform SPIRV-Cross renamed for GLSL (input comes out as _input, so GetShaderLocation("input") would bind nothing). RaylibGlslMapper
SD0636 raylib converter: a matrix or struct uniform. Matrix majorness through raylib's SetShaderValueMatrix is not proven by the raylib render gate, and struct members are not modeled; pass the values as float4 uniforms instead. RaylibGlslMapper
SD0637 Warning. raylib converter: a sampler bakes sampler_state entries (filter, address, ...). raylib keeps filtering and addressing on the Texture2D, so the shader cannot carry them; apply them with SetTextureFilter/SetTextureWrap. The entries are also listed in RaylibSampler.BakedSamplerState. RaylibGlslMapper
SD0640 Real-slangc Slang route (issue #302): slangc emitted a TEXTURE under a name it generated for a resource it hoisted out of an aggregate other than a global combined sampler: a struct global's field (struct M { Texture2D t; ... }; M gM; comes back as gM_t_0, or globalParams_gM_t_0 when the struct also holds data), a texture declared inside a cbuffer/ParameterBlock (C_T_0), an entry-point uniform Texture2D T (entryPointParams_T_0), or a combined sampler nested in one of those (gM_c_texture_0). That name would be the texture's parameter in the compiled effect, no name the author wrote identifies it, and the reference compiler has no convention to follow (fxc rejects a texture inside a struct, X3090, measured through mgfxc 3.8.4.1). Located at the aggregate's declaration in the entry source when the raw text shows it. Declare the texture as a global of its own (Texture2D Name; with a SamplerState, or a combined Sampler2D Name;); both reflect as Name. A hoisted SAMPLER alone is not an error: nothing sets a sampler by name. SlangCompiler, SlangcHoistedResourceNames
SD0641 Real-slangc Slang route (issue #302): the author's name for a combined sampler's texture cannot be used. Either slangc's output declares the generated name twice, because the source also declares a global spelled like it (Sampler2D Comb; Texture2D Comb_texture_0;: slangc keeps neither apart, measured), or slangc's output already uses the author's name for something else (a cbuffer member of the same name from a namespace slangc flattened). Located at the combined sampler's declaration when the raw text shows it. Rename one of the two. SlangCompiler, SlangcHoistedResourceNames
SD0642 Real-slangc Slang route (issue #302): a texture in slangc's output has the shape of a generated name (<global>_<field>_<n>), no file ShadowDusk preprocessed (the entry source and the modules it imports by quoted path) spells it or declares a global it could have been hoisted from, and the source imports files that were not read (an import by module name is not followed). It may be the author's own global in that file or a hoist of one, and ShadowDusk will not guess: renaming an author's parameter and leaving a generated name in the effect would both break effect.Parameters lookups silently. Declare the texture in the entry source, or in a module imported by quoted path. SlangCompiler, SlangcHoistedResourceNames
SD0643 Real-slangc Slang route (issue #323): two global declarations of one simple name that slangc's -no-mangle output cannot keep apart, both named in the message with their file, line and column: two globals (a resource, a combined sampler, a struct- or ParameterBlock-typed global, an implicit or uniform constant-buffer member, a static or static const) or two cbuffer blocks in different namespaces (nested, dotted and :: forms alike, and a namespaced one beside a plain one), or two modules that each declare the same plain global. Measured on slangc v2026.14.1: it emits ONE declaration for the pair, so the shader silently reads one texture or value where two were declared (namespace A { Texture2D T; } namespace B { Texture2D T; } comes back as one T both reads use; two static const of one name take the first initializer), and two same-named constant-buffer members crash it outright (exit 0xC0000005, nothing on stderr). Checked before slangc runs on the raw entry text when nothing can rewrite it, confirmed by slangc's own -E output when a directive or a -D value could (one run, paid only by a source whose raw text shows a candidate pair; a pair in mutually exclusive #if branches is cleared), and again on every text the issue #292 register pass read (the entry's -E text and the modules reached by quoted-path import), which is where a macro-formed or cross-module pair is found. Same-named functions and types are fine (slangc prefixes those with the namespace). Give every global variable, shader parameter and constant buffer a name that is unique across namespaces and imported modules. The pairs no read text shows (issue #337) are not caught; the constant-buffer variant then fails as the SD0622 crash report, which names this trigger. SlangCompiler, SlangcGlobalNameCollisions
SD0644 Real-slangc Slang route, OpenGL target: two combined samplers declare the same sampler register (Sampler2D A : register(s0); Sampler2D B : register(s0);), both named in the message, located at the second declaration. A combined sampler's sampler register is its GL texture unit (as mgfxc treats the legacy sampler2D X : register(sN)), and one unit holds one texture: fxc refuses the legacy pair (X4500, overlapping register semantics) and the DirectX targets refuse the Slang pair too, while the GL allocator would have moved the second texture silently. A combined sampler sharing its register with a split SamplerState is allowed (mgfxc accepts it). Give each combined sampler its own register, or leave it off. SlangCompiler, SlangcCombinedSamplerGlSlots
SD0645 Real-slangc Slang route (issue #469): the slangc child process did not exit within SlangCompiler.SlangcTimeout (60 seconds by default; Timeout.InfiniteTimeSpan disables it) and was killed, process tree included. The message names the run (slangc's path and its full argument list, so the entry point and stage are visible) and the limit. A run takes well under a second on a desktop and a few seconds on a starved CI runner, so a run still going after a minute is stuck, not slow; raise SlangcTimeout only for a host known to be that slow, and open an issue with the shader if it recurs on a fast one. A compile's CancellationToken also kills a running slangc, as OperationCanceledException, not this code. The limit covers handing slangc the source, its run and the reading of its output (it is a kill, not just a bounded wait, so a child stuck before reading stdin is covered too); it cannot bound a hang inside the OS's own process creation. Only the process route; the in-process (browser) route has no child process. SlangCompiler
SD0650 The input is not a shader format the called ShaderConverter method reads (kind UnsupportedInput): no HLSL technique block, no Slang [shader(...)] entry attribute or import / module declaration, and no name hint naming one; or GLSL, which the separate ShadowDusk.ShaderToy package converts. Nothing was compiled, so a caller that chains shader loaders can hand the input to the next one. ShaderConverter
SD1900 Browser/WASM DXC backend failed. JsDxcShaderCompiler
SD1901 Browser/WASM SPIRV-Cross backend failed. JsSpirvToGlslTranspiler
SD1902 Browser/WASM vkd3d backend failed. WasmVkd3dShaderCompiler
SD1903 Synchronous Compile() called before the WASM compiler was initialized. WasmCompilerInitialization, WasmSlangCompiler (the slangc module, issue #257)
SD1904 Browser/WASM full-Slang route (issue #257): the shadowdusk-slangc WebAssembly module (the pinned slangc, run in-process) could not be loaded from _content/ShadowDusk.Slang.Wasm/. The message names the module and carries the load error verbatim. A DXC or vkd3d module that fails to load keeps its own code (SD1900/SD1902). WasmSlangCompiler, SlangcModule
SD1905 Browser/WASM full-Slang route: the slangc WebAssembly module trapped while compiling (a stack overflow on extremely deep source, an out-of-bounds access, an abort). A runtime failure of the module, not a slangc diagnostic: native slangc may accept the same source. The module instance is discarded and the next load starts a fresh one. WasmSlangCompiler
SD1906 Browser/WASM host (issue #272): the requested PlatformTarget is not a browser export target. The browser host exports OpenGL, Vulkan, DirectX (DX11) and FNA; DirectX12 has no in-browser path (its DXC module returns SPIR-V only, and DX12 DXIL must be validated and signed by the Windows-only dxil.dll), so it is refused before any WebAssembly module loads or runs, on both the .fx and the full-Slang route. The message names the target and the host. A set CompilerOptions.Profile is checked by its GraphicsTarget, as the pipeline resolves it. Metal is not refused here: it gets SD0200, as on every host. Compile DX12 with the desktop library, the CLI or the MGCB plugin on Windows. WasmShaderCompiler, WasmSlangCompiler (BrowserHostTargets)
SD1907 Browser/WASM host (issue #271): the DXC, SPIRV-Cross or vkd3d-shader WebAssembly module trapped while compiling (a stack overflow on extremely deep source, an out-of-bounds access, an abort). A runtime failure of the module, not a compiler diagnostic: the desktop compiler may accept the same source. The message names the module and carries the trap text verbatim. The module instance is discarded and the next CompileAsync (or InitializeAsync) loads a fresh one; a synchronous Compile() in between reports SD1903. JsDxcShaderCompiler, JsSpirvToGlslTranspiler, WasmVkd3dShaderCompiler

X — CLI / general (mgfxc-style)

Code Meaning
X0000 A diagnostic from the underlying compiler, passed through as-is: either a parsed file:line:col entry (DXC emits no per-diagnostic codes) or, when nothing parses, the compiler's complete text VERBATIM as the message (never a generic sentence). The …with no diagnostics message form means the compiler failed while emitting no text at all.
X0001 Source file could not be read (I/O or access denied).
X0002 Output file could not be written (I/O or access denied).
X0003 Missing required CLI argument (<SourceFile> / <OutputFile>).
X0004 Unknown CLI profile.
X0005 Invalid --mgfx-version value (only 10 and 11).
X0006 Invalid /DxbcBackend value (only vkd3d, d3dcompiler).
X0007 CLI compile timed out (5-minute watchdog).
X0008 Invalid --target-runtime value (only monogame-gl, monogame-dx, monogame-gl-v11, kni-knifx, kni-knifx-v12, fna).
X0009 A CLI flag that requires a value (/I, --mgfx-version, --target-runtime, …) reached the end of the argument list with no value supplied.
X0010 Platform not supported by ShadowDusk (e.g. PlayStation4, XboxOne, Switch).
X0011 Invalid --input-format value (only auto, fx, glsl).
X0099 Unexpected internal error (catch-all; a bug if a consumer ever sees it).