microsoft / microsoft/typespec

Code model deserialization cannot resolve references first defined inside decorator arguments

Open
#11,981 1 comment 1 reaction 0 assignees View on GitHub
bug emitter:client:csharp
Dominant language
Java
Stars
5.9k
Forks
394
Avg merge
1d 23h
Merged PRs (30d)
104

Description

## Description

Reference-preserving code-model JSON can fail to deserialize when a shared object is first serialized inside a decorator argument and referenced later from the main code-model graph.

For example, the serialized shape can effectively contain:

```json
{
"decorators": [
{
"name": "example",
"arguments": {
"value": {
"$id": "2463",
"name": "SharedModel"
}
}
}
],
"models": [
{
"$ref": "2463"
}
]
}
```

The C# code-model reader currently captures decorator arguments as opaque JSON/BinaryData. Because those nested values are not deserialized through the shared TypeSpec reference resolver, `$id: 2463` is never registered. Deserialization later reaches `$ref: 2463` in the ordinary model graph and fails with an error similar to:

```text
System.Text.Json.JsonException: cannot resolve reference 2463
```

We encountered this while upgrading the Azure management-plane C# generator. The immediate SDK-side mitigation removes model-valued arguments from known decorators before serializing the code model, but this is fragile: new decorators can reintroduce the same graph shape, and consumers may legitimately need those arguments.

## Suggested change

Decorator arguments should participate in the same reference-resolution pass as the rest of the code model. Possible approaches include:

1. Deserialize decorator argument values through the shared `TypeSpecReferenceResolver` rather than capturing their raw JSON directly.
2. Pre-scan the complete JSON document to register all `$id` nodes before resolving `$ref` nodes, including IDs nested under opaque or extensibility properties.
3. Preserve raw decorator JSON only after reference metadata has been registered or normalized, so opaque payload handling cannot hide graph identities from the resolver.

The desired behavior is that a `$ref` remains resolvable regardless of where the corresponding `$id` first appears in the serialized document.

## Impact

This failure blocked regeneration of multiple Azure management SDK libraries after a dependency upgrade. Sanitizing decorator arguments avoids the immediate exception but loses metadata and does not address the underlying deserializer behavior.

Contributor guide

Open the contributing guide

Research direction

Start with the C# code-model reader and the shared TypeSpecReferenceResolver, then reproduce the failure using the serialized JSON shape in the issue. Trace how decorator arguments are captured and how the later model $ref is resolved. Done means an ID first found inside decorator arguments can resolve later without losing the argument metadata.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, csharp, json
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.