Describe the bug
Summary
When an @error model has a property whose type is a non-string literal (e.g. status: 404), @typespec/http-server-csharp emits a constructor whose default parameter is typed object with the literal as its default value:
public NotFoundProblem(string title, object status = 404) : base(400, ...)
This violates C# language rule CS1763: a default parameter of a reference type other than string may only be initialised with null. The generated file does not compile.
Within the same generated class the property itself is correctly typed int:
public int Status { get; } = 404;
— so the in-class typing is inconsistent even before CS1763 fires.
Versions
| Package |
Version |
@typespec/compiler |
1.12.0 |
@typespec/http |
1.12.0 |
@typespec/rest |
0.82.0 |
@typespec/http-server-csharp |
0.58.0-alpha.28 |
| Node |
22.x / 24.x (both confirmed) |
| .NET SDK |
10.0.203 (any LTS) |
Trigger
The bug requires all three:
- A
model decorated with @error.
- A property on that model whose type is a non-string literal (numeric or boolean).
- An
op that references the @error model in its return type so the emitter actually emits it.
Plain models (without @error) emit literal-typed properties cleanly as read-only properties — only @error triggers the all-fields-constructor code path that produces the broken signature.
Minimal repro source
import "@typespec/http";
import "@typespec/rest";
using Http;
using Rest;
@service(#{ title: "Repro" })
namespace Repro;
// Control: plain model with the same literal pattern — emits cleanly.
model Config {
name: string;
version: 1;
}
// Trigger: @error model with a numeric-literal-typed property.
@error
model NotFoundProblem {
title: string;
status: 404;
}
@route("/config")
interface ConfigApi {
@get
@route("{id}")
get(@path id: string): Config | NotFoundProblem;
}
What gets emitted
Config.cs — the control, clean:
public partial class Config
{
public string Name { get; set; }
public int Version { get; } = 1; // ✅ legal
}
NotFoundProblem.cs — the bug:
public partial class NotFoundProblem : HttpServiceException
{
public NotFoundProblem(string title, object status = 404) : base(400, // ← CS1763
value: new { title = title, status = status })
{
Title = title;
Status = status; // ← would also fail (CS0029)
// if CS1763 weren't first
}
public string Title { get; set; }
public int Status { get; } = 404; // property is `int`, not `object` —
// inconsistent intra-class typing
}
Build error
NotFoundProblem.cs(15,53): error CS1763:
"status" is of type "object". A default parameter value of a reference type
other than string can only be initialized with null.
(Column 53 is the = 404 token.)
Expected behaviour
One of:
- Drop the literal-ness from the constructor signature and use the base scalar:
public NotFoundProblem(string title, int status = 404) : base(404, ...)
- Or fold the literal-typed property out of the constructor signature entirely (it is already pinned to
404 via the property initialiser):
public NotFoundProblem(string title) : base(404, ...) { ... }
Either is valid C# and preserves the TypeSpec contract.
Workaround
Replace the literal with the base scalar type:
@error
model NotFoundProblem {
title: string;
- status: 404;
+ status: int32;
}
The trade-off: the TypeSpec source loses the per-subtype status discriminator the API contract intended. RFC-9457-style problem-detail subtypes ("this variant always means HTTP 404") cannot be expressed.
Reproduction
The Playground does not run @typespec/http-server-csharp, so a standalone repo is needed: https://github.com/TKI-Chemnitz/typespec-http-server-csharp-cs1763-repro.
The repo contains exactly the minimal pieces:
main.tsp — ~20 lines (control model + @error trigger model + one op).
package.json — exact version pins (no caret/tilde).
pnpm-lock.yaml — lockfile committed.
tspconfig.yaml — minimal, only the C# server emitter.
Repro.csproj — net10.0 library, ImportDirectoryBuildProps=false, FrameworkReference Microsoft.AspNetCore.App.
To reproduce:
corepack pnpm install
corepack pnpm exec tsp compile main.tsp
dotnet build Repro.csproj
Or in one go:
Expected output: dotnet build exits with one CS1763 error pointing at tsp-output/@typespec/http-server-csharp/generated/models/NotFoundProblem.cs(15,53).
Checklist
Describe the bug
Summary
When an
@errormodel has a property whose type is a non-string literal (e.g.status: 404),@typespec/http-server-csharpemits a constructor whose default parameter is typedobjectwith the literal as its default value:This violates C# language rule CS1763: a default parameter of a reference type other than
stringmay only be initialised withnull. The generated file does not compile.Within the same generated class the property itself is correctly typed
int:— so the in-class typing is inconsistent even before CS1763 fires.
Versions
@typespec/compiler1.12.0@typespec/http1.12.0@typespec/rest0.82.0@typespec/http-server-csharp0.58.0-alpha.2822.x/24.x(both confirmed)10.0.203(any LTS)Trigger
The bug requires all three:
modeldecorated with@error.opthat references the@errormodel in its return type so the emitter actually emits it.Plain models (without
@error) emit literal-typed properties cleanly as read-only properties — only@errortriggers the all-fields-constructor code path that produces the broken signature.Minimal repro source
What gets emitted
Config.cs— the control, clean:NotFoundProblem.cs— the bug:Build error
(Column 53 is the
= 404token.)Expected behaviour
One of:
404via the property initialiser):Either is valid C# and preserves the TypeSpec contract.
Workaround
Replace the literal with the base scalar type:
@error model NotFoundProblem { title: string; - status: 404; + status: int32; }The trade-off: the TypeSpec source loses the per-subtype status discriminator the API contract intended. RFC-9457-style problem-detail subtypes ("this variant always means HTTP 404") cannot be expressed.
Reproduction
The Playground does not run
@typespec/http-server-csharp, so a standalone repo is needed: https://github.com/TKI-Chemnitz/typespec-http-server-csharp-cs1763-repro.The repo contains exactly the minimal pieces:
main.tsp— ~20 lines (control model +@errortrigger model + oneop).package.json— exact version pins (no caret/tilde).pnpm-lock.yaml— lockfile committed.tspconfig.yaml— minimal, only the C# server emitter.Repro.csproj— net10.0 library,ImportDirectoryBuildProps=false,FrameworkReference Microsoft.AspNetCore.App.To reproduce:
corepack pnpm install corepack pnpm exec tsp compile main.tsp dotnet build Repro.csprojOr in one go:
Expected output:
dotnet buildexits with one CS1763 error pointing attsp-output/@typespec/http-server-csharp/generated/models/NotFoundProblem.cs(15,53).Checklist