Table of Contents

Generator and analyzer diagnostics

The generator reports problems as build diagnostics with ids CSG001 to CSG300, each pointing at the attribute or expression that caused it. The table is generated from the analyzer's release files by tools/documentation/validate-generator-diagnostics.mjs, which the documentation gate runs with --check so the list cannot drift from what ships.

Id Severity Title
CSG001 Error Layout does not compile
CSG002 Error Layout file not found
CSG003 Error Generated name collision
CSG004 Warning Unknown root declaration
CSG005 Error Attributed class must be partial
CSG006 Error Custom codec declaration is invalid
CSG010 Error C# 12 or later is required
CSG011 Error The Views surface needs views
CSG012 Warning A CStructSharp project property is not valid
CSG013 Error RuntimeByteOrder is not supported here
CSG014 Error A value-type shape is not supported here
CSG015 Error A scalar shape is not supported here
CSG016 Info A generated layout is never used
CSG017 Info A generated layout generates more than its uses need
CSG018 Warning The conditions on a member can never hold
CSG019 Info A constraint label names different conditions
CSG020 Warning A magic follows a variable-size member
CSG021 Info A layout qualifies for the scalar shape
CSG022 Info A layout qualifies for value-type shapes
CSG023 Info Members of a generated layout are never read
CSG100 Error Mapped type must be partial with a parameterless constructor
CSG101 Error Mapped member type is not mapped
CSG102 Warning Mapped member has no layout counterpart
CSG200 Warning Path does not resolve against the layout
CSG201 Info Parse selects a root that is not a struct
CSG300 Warning dynamic over a parsed value in a trimmed or AOT-published project

The CSG0xx ids come from [CStructLayout], CSG1xx from [CStructMapped], and CSG2xx/CSG3xx from the analyzer that looks at how a project uses the runtime API.

CSG001 - Layout does not compile

Cause. The layout text (inline or in a .cstruct file) fails to parse or compile. This is an error, and the message is the runtime's own - the same text new CStruct(text) would throw at run time.

[CStructLayout("struct header { uint32 length; uint8 tail[length + ]; }")]
public static partial class Broken { }
// CSG001: Unexpected token '}' in array length expression ...

Fix. Correct the layout. The message names the line and column; the language manual covers every construct.

CSG002 - Layout file not found

Cause. [CStructLayout(File = "...")] names a file that is not among the project's AdditionalFiles. An error.

Fix. The package's build props include every .cstruct file under the project automatically; a file with another extension, or one outside the project, needs <AdditionalFiles Include="path" /> in the project file.

CSG003 - Generated name collision

Cause. Two layout identifiers become the same C# name after PascalCase conversion (chunk_type and ChunkType), a generated type is named like the containing class, the class itself is named like a generated member (Layout, Parse, Update, ...), a conditional member's Has<Member> flag or a fixed array's view slice <Member>Bytes is spelled by another member, or a member the view exposes is named bytes or to_object (the view's own Bytes and ToObject), or an integer #define (which becomes a constant of the class under its own name) is named like a generated member or type. An error, because C# cannot compile the result.

Fix. Rename the identifier in the layout, rename the class, use [CStructLayout(KeepNames = true)] to keep the C spellings, or Views = false when only a view member collides.

CSG004 - Unknown root declaration

Cause. Root = "name" names a declaration the layout does not have. A warning: the class still generates, and the plain Parse/Serialize use the compiler's default root (the last struct declared) instead.

Fix. Spell the root as the layout declares it, or drop Root to accept the default.

CSG005 - Attributed class must be partial

Cause. The attributed class is not static partial, or a type that contains it is not partial, so the generator has nowhere to add members. An error.

Fix. Declare the class public static partial class Name and mark every containing type partial.

CSG006 - Custom codec declaration is invalid

Cause. An entry of Codecs = [...] is not "name", "name:size", "name:size:alignment", or "name:*:alignment", repeats a built-in type, or has an alignment that is not a power of two. An error.

Fix. Declare each codec as the custom codec recipe shows and implement CreateCodecs() to return one instance per declaration, in order.

CSG010 - C# 12 or later is required

Cause. The project's language version is older than C# 12, which the generated code needs (collection expressions, static abstract interface members). An error.

Fix. Add <LangVersion>12</LangVersion> (or newer) to the project file; .NET 8 and later default to it.

CSG011 - The Views surface needs views

Cause. Surface = GeneratedSurface.Views generates only views, and Views = false turns views off, so together they would generate nothing. An error. Either value may come from the attribute or from the project's CStructSharpSurface and CStructSharpViews properties.

Fix. Remove Views = false, or choose GeneratedSurface.Reader or GeneratedSurface.Full.

CSG012 - A CStructSharp project property is not valid

Cause. One of the CStructSharp* build properties that set a project-wide default (see Project defaults) has a value the generator does not understand, for example <CStructSharpSurface>Tiny</CStructSharpSurface>. A warning: the property is ignored and the library's default applies.

Fix. Use a valid value: Full, Reader, Parser or Views for CStructSharpSurface; SysV or Msvc for CStructSharpBitfieldPacking; LowBitFirst or HighBitFirst for CStructSharpBitfieldAllocation; 1, 2, 4 or 8 for CStructSharpPointerSize; 32 or 64 for CStructSharpCLongWidth; Class, Struct or Auto for CStructSharpShape; Constraint or FormatExceptions for CStructSharpConstraintFailures; a whole number from 1 to 65536 for CStructSharpMaxValueBytes; true or false for the flag properties.

CSG013 - RuntimeByteOrder is not supported here

Cause. RuntimeByteOrder = true (or the project's CStructSharpRuntimeByteOrder) cannot be generated: the layout uses the full surface, which writes and so encodes one byte order, or a bitfield sits in a different place when the layout is compiled big-endian than when it is compiled little-endian, or the layout does not compile in the opposite order. An error; the message names the reason and, for a bitfield, the field.

Fix. Use GeneratedSurface.Reader, Parser or Views, and give the bitfield members an order that does not move them (declare them with the same storage type, or separate runs with an ordinary member), or keep two layouts, one per order.

CSG014 - A value-type shape is not supported here

Cause. Shape = GeneratedShape.Struct (or the project's CStructSharpShape) cannot be generated for this layout: the surface is Full (its writers, Update setters and Records need classes) or Views (which generates no type), a struct is bigger than MaxValueBytes (1,024 unless raised), or a struct holds something a value type cannot: a union, a conditional member, a pointer, a runtime-sized or multidimensional array, a custom codec or a terminated string. An error; the message names the member and the reason.

Fix. Use GeneratedSurface.Reader or Parser, change the layout so every struct is fixed in size with the shapes listed above, raise MaxValueBytes, keep Shape = GeneratedShape.Class for that layout, or use Shape = GeneratedShape.Auto to take the value type only where it fits.

CSG015 - A scalar shape is not supported here

Cause. Shape = GeneratedShape.Scalar cannot be generated for this layout: the surface is Full or Views, or the layout is not one struct whose only member is a number, an enum or an identifier at offset 0 that fills the struct (a second member, an array, a bitfield, a nested struct, a pointer, a conditional member, a custom codec or an alignment that pads it). An error; the message names the reason.

Fix. Use GeneratedSurface.Reader or Parser and a one-member layout, or choose another shape.

CSG016 - A generated layout is never used

Cause. A [CStructLayout] class that no other assembly can see is not referenced by any code in this one, so everything generated for it is dead weight. Reported as info; once per class and only when the analysis is certain (no friend assembly, no [CStructMapped] class).

Fix. Delete the layout, or use it. Raise the severity in an .editorconfig to make a new unused layout a build error.

CSG017 - A generated layout generates more than its uses need

Cause. Every member of the layout that the code uses is also generated by a smaller Surface, or the layout generates views that no code names. Reported as info; the message lists the members used and the options to write.

The layout class 'Header' is used only through Parse; generate less with Surface = GeneratedSurface.Parser, Views = false

Fix. Write the suggested options on the attribute, or set them as project defaults. A call with a byte[] argument needs the Reader surface (the array overload); passing a ReadOnlySpan<byte> needs only Parser.

CSG018 - The conditions on a member can never hold

Cause. The @expect and @supports conditions of one member exclude every value its type can hold, so every read of the layout fails at that member. The analyzer compares the member with constants and #defined integers and combines the comparisons with &&, || and !; a bound outside the type is the simplest case. It reports only what it can prove: a condition that uses another member, a mask or arithmetic on the member is not reduced, and a layout that does not compile is left to CSG001. Reported as a warning at the layout text, for a [CStructLayout] attribute and for a literal passed to new CStruct or CStruct.GetOrCompile.

The conditions on 'a.big' can never hold: 'big > LIMIT' holds for no value of uint8 (0 to 255), so every read of this layout fails

Fix. Correct the bound (a uint8 is at most 255), or merge conditions that were meant as alternatives into one || condition.

CSG019 - A constraint label names different conditions

Cause. Two constraints of one layout carry the same label but test different conditions, for example the magic numbers of two structs in one file under "xfs.magic". A label is what a report shows to say which constraint failed, so a repeated label makes two failures look alike. Reported as info; repeating the same condition under one label is not reported.

Fix. Give each condition its own label ("xfs.sb.magic", "xfs.agf.magic"), or keep one label only where the condition is the same.

CSG020 - A magic follows a variable-size member

Cause. A member with an @magic condition comes after a member whose size depends on the data (a runtime-sized array, a string), so its offset is not known when the layout is compiled. The magic still works: it is checked as soon as its member has been read, with the conditions of the members in front of it held back until then. But Matches cannot evaluate it (it decodes only members at known offsets), and the members before it have to be read before the format is recognized. Reported as a warning.

Fix. Move the magic member to the front of the struct, or before the first variable-size member.

CSG021 - A layout qualifies for the scalar shape

Cause. A layout generated as classes (the default Shape) on the Reader or Parser surface is one struct with one number, enum or identifier at offset 0 that fills the struct, such as a magic number. A scalar Parse returns that value directly, so no class exists to allocate. Reported as info, once per class; a layout that sets Shape is not second-guessed.

The layout class 'Magic' qualifies for Shape = GeneratedShape.Scalar: Parse can return the ushort itself and no type needs to be generated

Fix. Set Shape = GeneratedShape.Scalar (the caller then uses the value, not a .A member), or ignore the suggestion when you want the struct type. See value types and just the value.

CSG022 - A layout qualifies for value-type shapes

Cause. Every struct of the layout, on the Reader or Parser surface, is fixed in size and holds only numbers, enums, bitfields, nested structs, text and fixed one-dimensional arrays, and is no larger than MaxValueBytes. Generating them as struct values means a read allocates no object. Reported as info, once per class, and not when CSG021 applies.

The layout class 'Pair' qualifies for Shape = GeneratedShape.Struct: its structs are fixed in size and can be value types, so a read allocates no object

Fix. Set Shape = GeneratedShape.Struct, or GeneratedShape.Auto to take value types wherever a layout qualifies. A value type is copied when it is assigned or returned, so keep a large struct a class; ignore the suggestion when the code needs reference semantics.

CSG023 - Members of a generated layout are never read

Cause. A layout on the Reader or Parser surface generates a property for every named member, but no code in the project reads some of them: reserved fields, unknown fields, flags nobody checks. Reported as info, once per class, with the first eight names as Type.Member. A write to a property is not a read, and a layout that also writes (the Full surface serializes every member) is not checked. Like CSG016 it needs a class that no other assembly can see and stays quiet when a friend assembly or a [CStructMapped] class may use it.

The layout class 'Header' generates members that no code reads: Root.Reserved, Root.Present; declare bytes you do not need as '_' padding in the layout

Fix. For bytes the code will never need, rename the member to _ in the layout: it is then padding, read and skipped, with no property. Leave a member alone when the layout documents a format you want to keep complete, when a condition in the layout names it (a name used by an @expect or an array length is still needed by the reader even if no code reads the property), or when it is read only by code the analyzer cannot see (reflection, another assembly).

CSG100 - Mapped type must be partial with a parameterless constructor

Cause. A [CStructMapped] class is not partial, or has no parameterless constructor for the generated ReadFrom to create an instance. An error.

Fix. Declare the class partial and give it a parameterless constructor (an implicit one is enough).

CSG101 - Mapped member type is not mapped

Cause. A property of a mapped class has a class type that is neither [CStructMapped] nor implements ICStructMapped<T>, so the generator cannot map a nested struct into it. An error.

Fix. Mark the nested class [CStructMapped], or declare the property as StructValue to keep the value untyped.

CSG102 - Mapped member has no layout counterpart

Cause. With Layout given, a property matches no member of that layout by exact name, case-insensitively, or ignoring underscores. A warning: the property is left alone by ReadFrom and WriteTo.

Fix. Add [CStructMember("member_name")] or rename the property. A property that is not meant to be mapped needs no public setter: the mapper only considers public properties that can be both read and written.

CSG200 - Path does not resolve against the layout

Cause. A constant path - the path argument of any CStruct method, such as ReadValue, TryReadValue, GetAccessor, ResolveAddress, GetArrayLength or Update, or the declaration name of GetStructSizeInBytes - names a declaration or member that the layout does not have. The analyzer checks it when the CStruct's layout is visible at build time: new CStruct("...") or CStruct.GetOrCompile("...") with constant arguments and no compilation options, or a generated class's Layout. It compiles the layout with the same pointer size, alignment, byte order and attribute settings as the runtime. A warning, because the runtime would throw CStructPathException.

Wire.Layout.ReadValue(bytes, "header.lenght"); // CSG200: no member 'lenght' in 'header'

Fix. Correct the path; the message lists the members that exist.

CSG201 - Parse selects a root that is not a struct

Cause. CStruct.Parse is called with a root that the visible layout declares as a union, an enum, or a scalar. Reported as info: Parse returns structs only, so the call fails at run time.

Fix. Use ReadValue for a union or a scalar root.

CSG300 - dynamic over a parsed value in a trimmed or AOT-published project

Cause. A StructValue (or UnionValue) is bound as dynamic in a project that sets PublishAot or PublishTrimmed; the runtime binder is not available there. A warning.

Fix. Read members through the indexer, Get<T>, or a mapped class, which need no runtime binding.