Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Repro — @error model with numeric-literal property → CS1763

Minimal reproduction of a bug in @typespec/http-server-csharp that emits a non-compilable C# constructor when an @error model has a property whose type is a numeric literal (e.g. status: 404).

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
.NET SDK 10.x (any LTS works)

Pinned exactly — no caret/tilde.

Reproduction

# 1. Install (uses corepack-shipped pnpm 10.10.0)
corepack pnpm install

# 2. Emit
corepack pnpm exec tsp compile main.tsp

# 3. Build the emitted C#
dotnet build Repro.csproj

Or in one go:

corepack pnpm run repro

Expected outcome (today, alpha.28):

tsp-output\@typespec\http-server-csharp\generated\models\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.

TypeSpec source (main.tsp)

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

The plain model Config with the literal version: 1 is emitted idiomatically: a read-only int property with the literal value as its initializer. No constructor is generated for a non-@error model.

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) but CS1763 fires first
    }
    public string Title { get; set; }

    public int Status { get; } = 404;     // and the property is `int`, not `object` —
                                          // the type mapping is inconsistent within the same file
}

Two things are wrong here:

  1. CS1763. object x = <non-string non-null literal> is not a legal default-parameter expression in C#. The language rule limits reference-type defaults to null (and string defaults to string-literal). The emitter types the constructor parameter as object but supplies the integer literal as the default — a contradiction.
  2. Inconsistent intra-class typing. The auto-generated property public int Status { get; } = 404; correctly maps the literal 404 to a non-nullable int. The constructor signature for the same property is object status = 404. Even if CS1763 didn't trip, the constructor body Status = status would fail with CS0029 (no implicit objectint).

A correct mapping would emit either of:

// Option A — drop the literal-ness, treat as int with a default
public NotFoundProblem(string title, int status = 404) : base(404, ...)

// Option B — fold the literal away from the constructor signature
public NotFoundProblem(string title) : base(404, ...) { ... }

Why only @error triggers it

@error causes the emitter to generate an all-properties constructor on the derived HttpServiceException so the model can be thrown directly. Non-@error models don't get such a constructor, so the numeric-literal-as-default-parameter code path never runs for them.

Workaround

Replace the numeric literal type 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. Downstream OpenAPI consumers no longer see „this variant means HTTP 404".

Related upstream issues

Files in this repro

  • main.tsp — TypeSpec source, ~20 lines.
  • tspconfig.yaml — emitter config.
  • package.json — exact version pins.
  • Repro.csproj — minimal SDK-style Microsoft.NET.Sdk library (targeting net10.0) that the .NET implicit Compile pattern picks up the emitted tsp-output/**/*.cs from.

About

Minimal repro: @typespec/http-server-csharp 0.58.0-alpha.28 emits a CS1763-invalid `object x = N` default-parameter constructor for @error models whose property has a numeric-literal type (e.g. `status: 404`).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages