TypeSpec emitter and versioning gotchas (issue-grounded)
Field failure modes from the microsoft/typespec issue trail: cases where valid-looking TypeSpec
compiles but the emitted OpenAPI is wrong or incomplete, version-track traps, and emitters that don't
exist yet. Complements the decorator-grounding rules in ../../SKILL.md (Anti-Hallucination
Rule) - that section stops you inventing decorators; this bundle catches the surprises in correct-but-subtle specs.
Sources: microsoft/typespec issues/PRs and release notes. Date checked: 2026-08-26. TypeSpec releases
the whole package set roughly monthly (first week of each month); re-verify version pins and issue states if this file is >30 days stale.
Version-track trap (verify before every upgrade)
@typespec/* and @azure-tools/typespec-* packages do not share one version. As of 2026-08-26 the latest published
stable versions sit on multiple independent tracks (ignore any -dev/next prereleases when pinning):
| Track | Packages | Latest stable |
|---|---|---|
| Graduated (1.x stable) | @typespec/compiler, @typespec/http, @typespec/openapi3 |
1.15.0 (2026-08-11) |
| Pre-1.0 core libs | @typespec/rest, @typespec/versioning, @typespec/xml, @typespec/streams, @typespec/sse, @typespec/protobuf |
0.85.0 (2026-08-11) |
| Azure tools (independent) | @azure-tools/typespec-azure-core, -azure-resource-manager, -autorest, -client-generator-core |
0.71.0 / 0.71.0 / 0.71.0 / 0.71.2 (2026-08-26) |
Implications:
- Don't assume a single version number. A spec can legitimately have
@typespec/compiler@1.15.0alongside@typespec/versioning@0.85.0and@azure-tools/typespec-azure-core@0.71.0. The Azure packages currently share a 0.7x family but still version independently of each other and of the core track. Pin each package to its own current npm version and upgrade the set together. - The
typespec-azure@X.Y.ZGitHub monorepo tag is not a package version. Atypespec-azure@0.70.xrelease tag can ship@azure-tools/typespec-azure-core@0.71.0- resolve the real version withnpm view <package> version, never from the monorepo tag number. - Upgrading the compiler requires a clean dependency reinstall, not just a version bump. Bumping in
package.jsonwithout removingnode_modulesproducedERR_MODULE_NOT_FOUND(ESM resolution / pnpm hoisting) until a clean reinstall. Deletenode_modules+ lockfile and reinstall after a compiler bump. (#10034) - Re-run compile after any compiler upgrade, not just a version bump of deps: recent stable releases changed file-level
usingresolution and extended emitter options - valid specs can emit different output across the jump. - Stay current: most emitter bugs below are fixed in recent releases; a stale pin is the main way to still hit them.
Currency note (verified 2026-08-26): latest stable compiler is 1.15.0 (2026-08-11). The 1.14/1.15 releases added project-scoped config and feature flags, graduated the
internalmodifier, and extendedenum-strategy: annotated- no decorator-surface break to the patterns this skill teaches. The Azure packages sit on their own family:@azure-tools/typespec-azure-core0.71.0,-azure-resource-manager0.71.0,-autorest0.71.0, TCGC 0.71.2. TheSdkOperationGroup→SdkClientconsolidation lives in@azure-tools/typespec-client-generator-core(TCGC), not in azure-core - re-verify withnpm viewbefore relying on it.
Emit-time gotchas (compiles clean, OpenAPI is wrong)
| Symptom | Cause / guard | Source |
|---|---|---|
| Error responses land under HTTP 200 instead of 400/401/etc. | @statusCode is not reliably extracted when it arrives through an alias to a generic model (status code passed via a type parameter). Confirmed emitter bug. Guard: prefer extends/is on a concrete error model, and inspect the emitted OpenAPI to confirm each error response is under its real status code - don't trust that the alias propagated it. |
#9034 |
Union → OpenAPI shape isn't what you expect (missing oneOf, awkward allOf, discriminator not applied) |
Union emission depends on the target OpenAPI version (3.0 has no clean union story; 3.1/3.2 do) and on using an explicit @discriminator. Most "broken polymorphism" reports trace to a non-standard discriminator usage rather than a compiler bug. Guard: set the OpenAPI version deliberately in tspconfig.yaml, use @discriminator, and verify the emitted oneOf/discriminator block. |
#826 |
Operation @examples emit as empty {} for union/enum-containing types |
Reproduced specifically when the API is versioned (@versioned). Fixed in recent releases; if you see empty examples on a versioned spec, upgrade the compiler before debugging your spec. |
#9088 |
Can't constrain Record<T> keys with @pattern/@format |
By design today, Record<T> keys are always plain string - there's no way to express a key pattern or format; it won't appear in the OpenAPI. A Map<K,V> type is under consideration but not shipped. Don't promise validated map keys in the contract. |
#2842 |
Before trusting emitted output on an older pin, also search the tracker for these known emitter bugs:
multi-file openapi3 output (#10182) and query-parameter
explode defaults for invalid types (#10405). Confirm against
your installed version rather than assuming the behavior.
Workflow guard (reinforces the skill's core rule): a wrong-but-valid decorator silently omits OpenAPI fields.
Always tsp compile --emit @typespec/openapi3 and read the generated document - never --no-emit alone - and diff the
OpenAPI when upgrading any package across the three tracks above.
Emitters that don't exist yet - don't promise these
TypeSpec ships emitters for OpenAPI 3.x, JSON Schema, Protobuf, and - since July 2026 - GraphQL
(@typespec/graphql, first-party; plus the Azure @azure-tools/typespec-autorest Swagger 2.0 emitter).
These remain long-standing community requests that are not shipped in the box:
| Output | State | Source |
|---|---|---|
| GraphQL SDL | SHIPPED July 2026 - first-party @typespec/graphql emitter (initial release 2026-07-17). Use it for GraphQL output; this skill's contract-design guidance still scopes to REST/OpenAPI. |
#1390 closed as completed |
| AsyncAPI (message/event APIs) | Still no official emitter; POC / community effort only (e.g. third-party typespec-asyncapi). |
#2463 open |
| WebSocket contracts | Open feature request. | #4124 open |
If a task needs AsyncAPI or WebSocket output, say so explicitly and treat any third-party emitter as unverified Preview - do not present it as a first-party TypeSpec capability.
Evidence anchors
- Repo + issue trail: microsoft/typespec, open issues
- Releases: TypeSpec releases (compiler 1.15.0 latest, 2026-08-11)
- Docs + playground: typespec.io, playground