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 file 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
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). 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.

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 passed to ReadValue, ResolveAddress, GetArrayLength, Update, or UpdatePath on a CStruct whose layout is visible at build time (new CStruct("..."), CStruct.GetOrCompile("..."), or a generated class's Layout) names a declaration or member the layout does not have. 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.