Generator diagnostics
Every build-time diagnostic the source generator can raise, with its SCGDB id, what triggers it, and how to suppress or escalate it from .editorconfig.
Overview
Beyond emitting code, the source generator inspects your tables and .sql procedure files at build time and reports problems as standard Roslyn diagnostics. Each one has a stable SCGDB### id, shows up in the IDE error list and in dotnet build output, and points at the offending property, attribute, or .sql file.
Because they are ordinary compiler diagnostics, you control their severity from .editorconfig exactly like any analyzer rule. See Configuring severity. All diagnostics share the Socigy.DB category.
Table & column definitions
These fire on the [Table] class or property they describe, so the squiggle lands directly on your C# source.
| Id | Severity | Triggered when |
|---|---|---|
SCGDB001 |
Error | [AutoIncrement] is applied to a property whose type is not short, int, or long. |
SCGDB002 |
Error | [Encrypted] is combined with [ValueConvertor], [JsonColumn], or [RawJsonColumn] on the same property. See Encrypted columns. |
SCGDB016 |
Warning | A [Table] class declares no [PrimaryKey] column. Generated Update() / Delete() need a primary key to target rows. |
SCGDB017 |
Warning | A [Table] class has no mapped columns. |
SCGDB018 |
Error | A [Column("")] is given an empty or whitespace name. |
SCGDB023 |
Error | [Encrypted] is applied to a [PrimaryKey] or [AutoIncrement] column. Encrypted values are stored as non-deterministic bytea and cannot serve as a key. |
SCGDB024 |
Error | Two properties of the same [Table] map to one column name after snake_case normalization. |
SCGDB025 |
Error | A [Table] / [TableType] type is generic or nested. The generator would emit an uncompilable partial declaration. |
SCGDB026 |
Error | An [Index] names a property the table does not have, in its column list or in Include / DescendingColumns / NullsFirstColumns / NullsLastColumns. The index would be generated over a column that does not exist and the migration would fail to apply. Using nameof gets the same check from the compiler; this covers string literals. |
Call sites
These inspect where you call the generated API rather than how you declare a table, so they point at the
invocation in your own code. They run as a Roslyn analyzer rather than from the generator, which is what
lets them bind the generated methods and read the row type, the InsertFields value, and the keep list from
real symbols instead of matching on how the call happens to be written.
| Id | Severity | Triggered when |
|---|---|---|
SCGDB027 |
Info | An insert passes InsertFields.ServerDefaults while the row type has [Default] columns the call does not name in keep. Those columns are omitted from the INSERT, so the database default is written instead of whatever the row holds. |
SCGDB027 — ServerDefaults omits a `[Default]` column
InsertFields.ServerDefaults omits every [Default] column, whether or not the row carries a value for
it. That is deliberate and documented, but it is decided by an attribute in a different file from the call
site: adding [Default] to an existing column silently changes every ServerDefaults insert that does not
name it, with no compile error, no runtime error and no log line.
[Table("outbox")]
public partial class OutboxMessage
{
[PrimaryKey] public Guid Id { get; set; }
[Default(DbDefaults.Time.Now)] public DateTime OccurredAt { get; set; } // added later
public string Payload { get; set; } = "";
}
// Written before OccurredAt gained its [Default]. Still compiles, still runs — but OccurredAt
// now falls to the server default and the value assigned above never reaches the database.
await db.OutboxMessages.InsertMultipleAsync(messages, InsertFields.ServerDefaults);Two ways to resolve it, both reported in the message:
// Name the column, and supply its value yourself.
await db.OutboxMessages.InsertMultipleAsync(messages, [nameof(OutboxMessage.OccurredAt)]);
// Or omit it only where the row actually left it unset.
await db.OutboxMessages.InsertMultipleAsync(messages, InsertFields.ServerDefaultsWhenUnset);SCGDB027 defaults to Info, so it appears as an editor suggestion and stays out of build
output. A codebase can legitimately have hundreds of ServerDefaults call sites, and a warning on each
would be noise rather than signal. Promote it when you want the full list — typically once you have found
one column that silently took its default and want to know where else it can happen:It covers every way the library offers to insert — the generated context's table set
(db.Rows.InsertAsync(row, …)), the static methods on the row class, BulkCopy, and the fluent
row.Insert().ExcludeAutoFields() builder — and it reads the InsertFields value through a constant or a
shared field, not just when the enum member is written inline:
public const InsertFields ServerFilled = InsertFields.ServerDefaults; // still recognised
await db.Outbox.InsertAsync(row, ServerFilled);It stays quiet where it cannot be certain. A keep list whose contents are not visible at compile time — one
built at runtime, or passed as a variable — suppresses the diagnostic for that call rather than risking a
false report about a column you already handle.
SQL procedure files
These fire while processing procedure-mapping .sql files and attach to the .sql file itself.
| Id | Severity | Triggered when |
|---|---|---|
SCGDB003 |
Warning | A .sql file contains no {{Type}} / {{Type.Property}} placeholder. Suppress per-file with -- @ignore warning (see Suppressing the placeholder warning). |
SCGDB004 |
Error | A placeholder references a type that does not exist in the compilation. |
SCGDB005 |
Error | A {{Type.Property}} placeholder references a property that does not exist on the named type. |
SCGDB006 |
Error | A placeholder is malformed; it must be {{TypeName}} (table) or {{TypeName.PropertyName}} (column). |
SCGDB007 |
Error | A placeholder references a type that is not a [Table] / [FlagTable]. |
SCGDB008 |
Error | A placeholder's simple type name is ambiguous; use a fully-qualified name. |
SCGDB009 |
Warning | A -- @param is declared but never referenced in the SQL body. |
SCGDB010 |
Warning | The SQL body references @name but no matching -- @param declaration exists. |
SCGDB011 |
Warning | The -- @returns type cannot be resolved in the compilation. |
SCGDB012 |
Warning | A -- @param line is malformed; expected -- @param name: CSharpType. |
SCGDB013 |
Warning | A .sql file is registered as <AdditionalFiles> but lives outside Socigy/Procedures/, so it was ignored. |
SCGDB014 |
Warning | A .sql file has an empty body after its header and produced no method. |
SCGDB015 |
Error | Two procedure files resolve to the same method name in the same namespace group. Only the first is emitted. |
SCGDB009 and SCGDB010 analyse raw SQL text, so unusual constructs (PostgreSQL @@ operators, casts inside string literals) can occasionally produce a false positive. They are warnings by design. Silence an individual rule with .editorconfig if it does not fit your SQL style.Suppressing diagnostics
Per-file: `-- @ignore warning`
The missing-placeholder warning (SCGDB003) is silenced for a single .sql file by adding the directive to its header:
-- @ignore warning: optional free-form reasonSee Procedure mapping → Suppressing the placeholder warning.
Inline: `#pragma` and `[SuppressMessage]`
Diagnostics reported on a .cs location (the table, column, and call-site rules) can be suppressed inline like any analyzer warning:
#pragma warning disable SCGDB016
[Table("audit_log")] // intentionally key-less, append-only table
public partial class AuditLog { /* ... */ }
#pragma warning restore SCGDB016Configuring severity
Set any diagnostic's severity from .editorconfig. The section glob must match the file the diagnostic points at (.cs for table, column, and call-site rules, .sql for procedure rules), or use a global section:
# Promote the missing-primary-key warning to an error
[*.cs]
dotnet_diagnostic.SCGDB016.severity = error
# Make a missing schema placeholder a hard build error
[*.sql]
dotnet_diagnostic.SCGDB003.severity = error
# Silence "declared but unused parameter" everywhere
[*.sql]
dotnet_diagnostic.SCGDB009.severity = noneValid severities are error, warning, suggestion, silent, none, and default.
.editorconfig severity and the -- @ignore warning directive are independent and complementary. Use the directive to silence one file; use .editorconfig to change a rule across the whole project.