> For the complete documentation index, see [llms.txt](/llms.txt)

# SDK generation diagnostics

## SDK generation

Raised while a codegen engine emits an SDK, when the engine can tell in advance that the source it
would write cannot compile. Generation stops rather than writing it, so the failure names your spec
instead of the SDK's own runtime.

**These stop the one target, not the whole run.** When an engine refuses, `glotto generate` drops
that target and still writes every other one — a refused Swift SDK does not cost you your TypeScript
and Python SDKs. The run exits non-zero and names the target it could not build, so a CI pipeline
that asked for thirteen SDKs and received twelve fails rather than passing quietly.
`glotto generate` reports these before anything is written, so you can see the problem
without waiting for a build.

### Reserved model names

The `*_RESERVED_MODEL_NAME` codes below are one problem in thirteen languages: a schema whose type
name collides with a type the generated SDK itself uses. Left alone, your model silently takes over
the SDK's own references and the build fails with errors pointing at the SDK rather than at the
collision — or, in Elixir, does not fail at all and quietly replaces your model.

**Generation resolves this for you.** The affected SDK emits the model under a deterministic
alternative — `Data` becomes `DataModel`, and a second collision becomes `DataModel2` — and
generation reports every rename it applied. Only that language's type name changes; your other SDKs
keep the original name. To choose the name yourself, pin it per target with
`models: { Data: { name: { swift: MyName } } }`, which always wins over the automatic rename and
leaves your other SDKs alone; a [`rename_schema` transform](/docs/transforms#rename_schema) renames
it in *every* target instead.

**You will only see one of these diagnostics if the rename cannot be applied** — it names every
colliding schema and the identifier each one shadows. In practice that means one thing: you pinned
the name yourself, with `models: { Data: { name: { swift: … } } }`, onto an identifier that language
reserves. A pin is treated as a decision rather than a suggestion, so generation will not quietly
substitute a different name for the one you asked for — it refuses that target and tells you.
Choose another name, or remove the pin and let the automatic rename resolve it.

Two things hold for all thirteen. Names that merely *look* built-in are not affected: each engine
reserves only what its generated code actually names without qualification, which is why every
*safe* column below has entries in it. And the **fixed** half of each reserved set — the language
builtins and the SDK's own scaffolding — already covers every type that SDK **can** use, not only
the ones your current endpoints reach, so turning on streaming, pagination or a new auth scheme
cannot widen *that* half under a build that used to work. The **derived** half is where it can, and
that is the next paragraph's whole subject.

**One case cuts across every language, and it is a fact about your spec rather than about the
engine.** Alongside the fixed vocabulary above, every SDK also declares names *derived* from your own
IR keys — the shared baseline is one class or module per resource: an `orders` resource makes the
Swift SDK declare `public final class OrdersResource`, and a nested `pets`/`photos` pair makes
`PetsPhotosResource`. Because a derived name is a function of your own resource, operation and model
keys rather than of the language, it can appear on a spec that **used to build** — unlike the fixed
vocabulary, which a spec either always or never reaches. Adding a resource, turning on SSE for an
operation you already had, or growing a discriminated union is what creates the collision, not
anything Glotto changed between generations. The remedy is the same either way: rename the model, or
rename the resource, operation, event or discriminator value that produced the name it collided
with — and the diagnostic always names which one.

Most engines add one or more families beyond that shared resource case, and they differ enough to be
worth reading rather than assumed. Throughout — and in the table below — `<Resource>` is the
PascalCase join of a resource key path (a nested `pets`/`photos` gives `PetsPhotos`), `<Method>` a
method key, `<Union>` a discriminated-union model key, `<Member>` one of that union's discriminator
values, `<Event>` a key of an operation's `event_types` map, `<Scope>` a declared OAuth2 scope, and
`<Parameter>` an optional query parameter.

- **Swift** and **Rust** add one `<Method>StreamEvent` enum per streaming operation with event types
  — so turning on SSE for an operation you already had is enough to create a collision that a
  previous generate certified absent.
- **Dart** and **C#** add that same enum *and* one type per mapped event name, so a new key in an
  operation's `event_types` reserves a name of its own: a sealed class plus its variants in Dart, an
  `abstract record` plus its per-event variants in C#.
- **TypeScript** and **React Native** derive the same five families — `<Resource>Resource`, a
  `<Resource>ResourceWithRawResponse` sibling wherever that resource has buffered operations,
  `<Method>StreamEvent`, one `<Union><Member>` per discriminated-union member, and the
  `<Union>Unknown` catch-all. They also share a behavior worth knowing about even when the *build*
  stays green: TypeScript merges a same-named `interface` declaration into an existing one rather
  than rejecting it, so the compiler can accept the collision while your model's type silently means
  the SDK's instead.
- **PHP** and **Ruby** add one `<Resource><Method>Request` class per operation whose request body is
  an inline JSON or multipart object.
- **Kotlin** adds that same request-body family plus the stream-event pair
  (`<Resource><Method>StreamEvent` and one `<Resource><Method>StreamEvent<Event>` per mapped event) —
  and is worth knowing about even on a green build for a different reason: the Kotlin SDK emits one
  file per top-level type, so two declarations claiming one path means one of them never reaches
  disk, with no compiler error at all.
- **Java** collects all four of Kotlin's families *and* the discriminated-union pair, because it puts
  every type in one package. Two of its failure modes are silent, and they are **not** the same: a
  collision with a class nested in the generated client compiles clean, because `javac` binds the
  SDK's own reference to its own type and your schema is simply never used; and, separately, where
  two files would claim one path, one is dropped before the compiler runs — which is Kotlin's case.
- **Python**'s resource family is the largest of the thirteen: **four** names per node, where
  TypeScript's and React Native's are two and everyone else's is one. It emits a sync and an async
  accessor class, plus a `WithRawResponse` sibling for each where the node has at least one buffered
  method, so a single `orders` resource can reserve all four spellings at once. It adds a
  `<Union>Unknown` catch-all and no stream-event family at all — its SSE events are emitted as the
  model types your spec already carries, so there is no per-method union type to collide with.
- **Elixir** has the resource case with **no suffix** (an `orders` resource emits
  `defmodule Glotto.Orders`, so the reserved identifier is a bare `<Resource>`) plus the
  discriminated-union pair; see below for the failure it shares with Ruby, and the one thing only it
  has.
- **Go** derives the widest set of the thirteen: the resource accessors, a stream-event trio, a
  discriminated-union trio, a per-operation option type with one constructor per optional query
  parameter, and one member per declared OAuth2 scope — all of them sharing the one package-level
  namespace with the fixed half, because a Go package has no module boundary to keep them apart. Its
  *fixed* half, by contrast, holds nothing from the language at all: Go's builtins and stdlib types
  are reached under a package qualifier or spelled in lower case, so a PascalCase schema name can
  never shadow one.

Every row below follows one convention. **Collides with** lists the fixed vocabulary first (language
and runtime builtins the emitted code references or declares, unaffected by your spec), then the
SDK's own declared types (abbreviated to the handful worth recognizing, since several engines' full
lists run past thirty), then **every** derived family that engine has, phrased as
`one <X> per <key> in your spec`. The abbreviation applies to the first two lists and never to the
third — and that is a checked property rather than an editorial promise: our own CI derives the
third list by running each engine's derivation, and runs every identifier in the last two columns
through the same resolver `glotto generate` calls, so a row that understated what its engine reserves
fails our build rather than reaching you.

Two diagnostics in this family are not about *our* names at all.
`GLOTTO_REACT_NATIVE_COLLIDING_MODEL_NAMES` and `GLOTTO_TYPESCRIPT_COLLIDING_MODEL_NAMES` cover the
case where two of **your own** schemas emit the same type name — `foo_bar` and `fooBar` both become
`FooBar` — which would declare that type twice in one module. TypeScript merges two declarations of
one name rather than rejecting them, so the usual outcome is a green build shipping a public type
that is your two schemas folded together; only a mismatched pair (an interface beside a type alias)
is a `Duplicate identifier` error.

**You will normally never see either code**, because this is resolved the same way every other
collision is: one of the schemas keeps the name and the rest are renamed with the `Model` suffix and
a numeric tail — `FooBar`, `FooBarModel`, `FooBarModel2` — and every rename is announced when you
generate. The schema that keeps the name is the first of the group in sorted order, which depends
only on your own keys, so it does not change when you add or rename an unrelated schema.

The code is emitted in one case: you pinned `models.<M>.name.<target>` on the schema that would have
been renamed. Renaming over an explicit pin would give you a type name you did not ask for, so Glotto
refuses that target instead — every other target you configured still generates — and the message
names the sibling that keeps the name. Pin the other schema instead, drop the pin and let the
automatic rename run, or rename one of them everywhere with `rename_schema`.

| Code | Language | Collides with | Safe despite appearances |
| --- | --- | --- | --- |
| `GLOTTO_SWIFT_RESERVED_MODEL_NAME` | Swift | `String`, `Int`, `Data`, `Codable`, `Sendable`, `Locale`, `UUID`, `Task`; the SDK's own `Client`, `APIError`, `RequestOptions`, `RawResult`; `BinaryResponse`, `DownloadResult`, `BinaryByteSource`, `TransportBinaryByteSource` and `URLSessionBinaryByteSource` when binary downloads are declared; SDKs with binary downloads or WebSockets also reserve `StreamingTransport`, `StreamingTransportConfigurationError`, `StreamingHTTPBody`, `StreamingHTTPResponse`, `StreamingWebSocket`, `StreamingWebSocketMessage`, `StreamingWebSocketResponse`, `NIOStreamingTransport`, `GlottoNIOAbort`, `GlottoNIOConnection`, `GlottoNIOHTTPHandler`, `GlottoNIOInflater`, `GlottoNIOOpening`, `GlottoNIOSocketAbortHandler`, `GlottoNIOUpgradeValidator`, `GlottoNIOWebSocketHandler`, `InboundIn` and `OutboundIn` across platforms; and one `<Resource>Resource` per resource plus one `<Method>StreamEvent` per streaming operation in your spec | `Result`, `Error`, `Item`, `Pet` |
| `GLOTTO_TYPESCRIPT_RESERVED_MODEL_NAME` | TypeScript | `Response`, `Headers`, `Promise`, `Record`, `Blob`, `WebSocket`; the SDK's own `Client`, `ApiError`, `TelemetryContext`, `RetryBudget`, `Tokenizer`; and one `<Resource>Resource` per resource, a `<Resource>ResourceWithRawResponse` per resource with buffered operations, one `<Method>StreamEvent` per streaming operation, one `<Union><Member>` per discriminated-union member, and one `<Union>Unknown` catch-all per eligible union in your spec; `BinaryResponse` when your spec declares binary responses | `Error`, `Date`, `JSON`, `Math`, `Symbol` |
| `GLOTTO_RUST_RESERVED_MODEL_NAME` | Rust | `Result`, `Option`, `String`, `Vec`, `Box`; the SDK's own `Client`, `ApiError`, `RequestOptions`, `RawResult`, `TelemetryContext`, `HttpClient`, `Rng`; `BinaryResponse` and `DownloadResult` when binary downloads are declared; and one `<Resource>Resource` per resource plus one `<Method>StreamEvent` per streaming operation in your spec | `Error`, `Clone`, `Debug` |
| `GLOTTO_DART_RESERVED_MODEL_NAME` | Dart | `Future`, `Object`, `List`, `Duration`, `Uri`, `Stream`, `StreamController`, `Completer`, `Iterable`; the SDK's own `Client`, `ApiError`, `RawResult`, `TelemetryContext`, `TokenStore`; `BinaryDownload`, `DownloadResult`, `JsonResult` and `FutureOr` when binary responses are declared; and one `<Resource>Resource` per resource, one `<Method>StreamEvent` per streaming operation, and one `<Method>StreamEvent<Event>` per mapped event name in your spec | `Error` |
| `GLOTTO_KOTLIN_RESERVED_MODEL_NAME` | Kotlin | `List`, `Map`, `Any`, `Unit`; the SDK's own `Client`, `Response`, `ApiError`, `RawResult`, `TokenStore`, `OAuthTokenResponse`, `TelemetryContext`; `BinaryExchange`, `BinaryResponse` and `DownloadResult` when binary responses are declared; and one `<Resource>Resource` per resource, one `<Resource><Method>Request` per inline-object request body, one `<Resource><Method>StreamEvent` per SSE operation, one `<Resource><Method>StreamEvent<Event>` per mapped event name, one `<Union><Member>` per discriminated-union member, and one `<Union>Unknown` catch-all per eligible union in your spec; plus, per documented non-2xx status in that spec, one typed-error class — the mapped name where the status has one (a documented 404 reserves `NotFoundError`) and `Status<NNN>Error` where it does not | `Result`, `Error`, `Slot`, `READ`, `Set`, `Sequence` |
| `GLOTTO_CSHARP_RESERVED_MODEL_NAME` | C# | `Task`, `Stream`, `Exception`, `Guid`, `Encoding`; the SDK's own `Client`, `ApiError`, `RequestOptions`, `Response`, `TelemetryContext`; and one `<Resource>Resource` per resource, one `<Method>StreamEvent` per streaming operation, one `<Method>StreamEvent<Event>` per mapped event name, and one `<Union><Member>` per discriminated-union member and one `<Union>Unknown` catch-all per eligible union, in your spec; plus, per documented non-2xx status in that spec, one typed-error class — the mapped name where the status has one (a documented 404 reserves `NotFoundError`) and `Status<NNN>Error` where it does not; when your spec declares binary responses, `BinaryResponse`, `DownloadResult` and the emitted test helper `BinaryTransferPeer` | `String`, `Object`, `Enum` |
| `GLOTTO_JAVA_RESERVED_MODEL_NAME` | Java | `String`, `Object`, `Integer`, `Thread`; the SDK's own `Client`, `Response`, `RequestOptions`, `TokenStore`, `ApiError` and the agent-primitive helpers; `BinaryExchange`, `BinaryPayload`, `BinaryResponse` and `DownloadResult` when binary responses are declared; and, from your own spec, one `<Resource>Resource` per resource, a `<Resource><Method>Request` per inline request body, a `<Resource><Method>StreamEvent` per SSE operation and a `<Resource><Method>StreamEvent<Event>` per mapped event name, one `<Union><Member>` record per discriminated-union value, and one `<Union>Unknown` catch-all per eligible union; plus, per documented non-2xx status in that spec, one typed-error class — the mapped name where the status has one (a documented 404 reserves `NotFoundError`) and `Status<NNN>Error` where it does not | `List`, `Exception`, `Builder`, `Slot`, `Map`, `Optional`, `Record` |
| `GLOTTO_GO_RESERVED_MODEL_NAME` | Go | `Client`, `APIError`, `Result`, `Option`, `WithBaseURL`; `BinaryResponse` and `DownloadResult` when binary downloads are declared; and, in the same package-level namespace, one `<Resource>Resource` accessor per resource, a `<Method>StreamEvent` with its `<Method>StreamEventValue` marker and one `<Method>StreamEvent<Event>` per mapped event name, a `<Union><Member>` and `<Union>Value` and `<Union>Unknown` per discriminated union, a `<Method>Option` with one `With<Method><Parameter>` constructor per optional query parameter, and one `OAuth2Scope<Scope>` per declared OAuth2 scope | `Context`, `Reader`, `Time`, `Error`, `Duration`, `Writer`, `Handler` |
| `GLOTTO_PYTHON_RESERVED_MODEL_NAME` | Python | `Exception`, `Generic`, `Iterator`, `AsyncIterator`, `TypeVar`, `TypeAdapter`, `BaseModel`, `ConfigDict`, `Field`; the SDK's own `Client`, `AsyncClient`, `ApiError`, `RawResponse`, `RawResult`, `TelemetryContext`, `TokenStore`; and, per resource in your spec, all four of `<Resource>Resource`, `Async<Resource>Resource`, `<Resource>ResourceWithRawResponse` and `Async<Resource>ResourceWithRawResponse` (the last two only where the resource has a buffered method), plus one `<Union>Unknown` catch-all per eligible discriminated union; `BinaryResponse` and `AsyncBinaryResponse` when your spec declares binary responses | `Any`, `Enum`, `Callable`, `Protocol`, `Data`, `Result`, `Response`, `List`, `Dict`, `Optional` |
| `GLOTTO_RUBY_RESERVED_MODEL_NAME` | Ruby | `Data`, `Hash`, `Array`, `String`, `Integer`, `Time`, `JSON`, `URI`; the SDK's own `Client`, `Response`, `ApiError`, `RawResult`, `TelemetryContext`, `OAuth2Scopes` and its typed-error, OAuth and agent-primitive classes; `BinaryDownload` when binary responses are declared; and one `<Resource>Resource` per resource, one `<Resource><Method>Request` per inline-object request body, and one `<Union><Member>` per discriminated-union member and one `<Union>Unknown` catch-all per eligible union, in your spec; plus, per documented non-2xx status in that spec, one typed-error class — the mapped name where the status has one (a documented 404 reserves `NotFoundError`) and `Status<NNN>Error` where it does not | `Struct`, `Symbol`, `Regexp`, `READ`, `WRITE` |
| `GLOTTO_PHP_RESERVED_MODEL_NAME` | PHP | `String`, `Int`, `Array`, `Object`, `Float`, `Bool`, `Mixed` (matched case-insensitively); the SDK's own `Client`, `ApiError`, `RequestOptions`, `RawResult`, `Response`, `TokenStore`; and one `<Resource>Resource` per resource, one `<Resource><Method>Request` per inline-object request body, and one `<Union><Member>` per discriminated-union member and one `<Union>Unknown` catch-all per eligible union, in your spec; plus, per documented non-2xx status in that spec, one typed-error class — the mapped name where the status has one (a documented 404 reserves `NotFoundError`) and `Status<NNN>Error` where it does not; and `BinaryDownload` only when an operation declares a binary response | `Exception`, `Closure`, `Generator`, `Error` |
| `GLOTTO_REACT_NATIVE_RESERVED_MODEL_NAME` | React Native | `Response`, `Headers`, `Promise`, `Record`, `URLSearchParams`, `WebSocket`; the SDK's own `Client`, `ApiError`, `TelemetryContext`, `RawResponse`, `Uploadable`, `SecureTokenStore`; and, from your own spec, one `<Resource>Resource` per resource, a `<Resource>ResourceWithRawResponse` per resource with buffered operations, one `<Union><Member>` per discriminated-union member, one `<Union>Unknown` catch-all per eligible union, and a `<Method>StreamEvent` per streaming operation with event types; `BinaryResponse` when your spec declares binary responses | `Map`, `Error`, `Date`, `Set`, `Symbol`, `JSON` |
| `GLOTTO_ELIXIR_RESERVED_MODEL_NAME` | Elixir | The SDK's own `Client`, `ApiError`, `RawResponse`, `RawResult`, `TokenStore`, `Webhook`, `SdkTest`, the agent-primitive helpers (`Tokens`, `Tokenizer`, `VectorMath`, `RetryBudget`, …) and the optional `OAuth` / `GraphQLClient` / `EventClient` / `WebSocketConnection` modules; plus, from your own spec, a bare `<Resource>` per resource (**no suffix**, unlike every other engine), one `<Union><Member>` per discriminated-union variant, and one `<Union>Unknown` catch-all per eligible union, and `BinaryDownload` when binary responses are declared | `Map`, `String`, `Enum`, `Jason`, `Req`, `Kernel`, `Keyword` — every Elixir and dependency module is namespaced away from yours |
| `GLOTTO_REACT_NATIVE_COLLIDING_MODEL_NAMES` | React Native | Another schema of **your own** — two `models` keys that case onto one type name (`foo_bar` and `fooBar` both emit `FooBar`, as do `FooBar` and `foo_bar`). Renamed automatically; the code is emitted only when you pinned `models.<M>.name.react_native` on the schema that would move | Two keys that stay distinct after casing, however similar they look |
| `GLOTTO_TYPESCRIPT_COLLIDING_MODEL_NAMES` | TypeScript | The same, for the TypeScript target — both engines resolve a schema's type name through the same rule, so the same pair collides in both | Two keys that stay distinct after casing, however similar they look |

Java and Kotlin reserve binary helper names only when an operation declares a binary response. Both then reserve `BinaryResponse`, `DownloadResult` and `BinaryExchange`; Java also reserves `BinaryPayload`. With no binary responses, a customer model named `BinaryResponse` keeps that name. Runtime references are qualified so customer models named Java `Runnable` or Kotlin `Set`, `Flow` and `Job` remain available.

Swift is the strictest case and the reason the behavior exists: it resolves a bare type name to the
declaration in the same module before any import, and offers no way to disambiguate. Kotlin's `Unit`
collides only in the Multiplatform packaging variant, and is reserved across all three so a variant
switch cannot break your build.

**Ruby is the quietest case**: it does not refuse a second definition of a name already declared in
scope — it rebinds it — so the collision produces no error at any moment a build could report one.
It is worth knowing about even though you should never meet it.

A schema named after a class
the Ruby SDK declares would replace that class outright while `ruby -c` passed, `require 'glotto'`
exited 0, and the SDK's own test suite stayed green. The failure would arrive as a `NoMethodError`
from inside the SDK the first time you called the affected method. That is why these names are
renamed rather than reported: there is no earlier moment at which anything could tell you. Two
constants that *look* like they belong on that list are not on it — `READ` and `WRITE` live inside
`Glotto::OAuth2Scopes`, which Ruby treats as a different constant from `Glotto::READ`, so a schema
of either name is left exactly as you wrote it.

**Elixir used to be Ruby's failure one step further, and is now the opposite — it fails loudly.**
Like Go's, and unlike every other engine's, its reserved set contains no language builtin at all: a
module named `Map` in your SDK's namespace is `Glotto.Map`, which never captures Elixir's own `Map`,
so schemas called `Map`, `String` or `Enum` are perfectly safe. What is not safe is a schema named
after a module the SDK declares itself.

Which way that fails depends on where the two `defmodule`s land, and the idiomatic package layout
moved them apart. Two declarations of one module name **in a single file** are accepted silently —
the later one simply replaces the earlier, and a schema named `Client` would compile cleanly with
your model's struct, `from_map/1` and `to_map/1` quietly gone. That was the old single-file SDK.
Each module now has its own file, and **across two files Elixir refuses outright**:

```
error: cannot define module Glotto.Client because it is currently being defined in lib/glotto/client.ex:1
```

The build stops; nothing is silently lost. So the rename is no longer protecting you from a missing
model — it is protecting you from an SDK that does not compile at all, which is a better failure but
still not one you should have to meet. It applies to your resource modules too: this engine names a
resource module after the resource key with **no suffix**, so a `pets` resource emits
`defmodule Glotto.Pets` and a schema named `Pets` collides with it. Like the Swift resource case
above, that one is a fact about your spec rather than about the engine, so adding the resource later
is what creates the collision — the diagnostic names the resource, and renaming or removing it
resolves the collision just as renaming the schema does.

### Two of your own schemas emitting one type name

A separate problem with a separate code, and no name of the SDK's involved. C# writes each model to
its own `Glotto/<Name>.cs` and derives that name in PascalCase, which is lossy — so two schemas that
differ only in casing or separators (`widget` and `Widget`, `foo_bar` and `FooBar`) emit **one** type
name and claim one file. Left alone, whichever file is written last destroys the other, the SDK
builds cleanly, and one of your schemas is simply not in it.

| Code | Language | When you see it |
| --- | --- | --- |
| `GLOTTO_CSHARP_MODEL_NAME_COLLISION` | C# | Two or more of your schemas emit the same C# type name, **and** a `models: { … : { name: { csharp: … } } }` pin sits on the one generation would otherwise rename |

**Generation resolves this for you in every other case.** The schema whose name is already spelled
exactly as the type it emits keeps that type name, and each other takes the model suffix — `FooBar`
and `fooBar` become `FooBar` and `FooBarModel`. Where no schema is spelled that way, the first key in
code-point order keeps it — and generation reports every rename it applied, exactly as it does for a [reserved
model name](#reserved-model-names). Only the C# type name changes; your other SDKs keep both original
names. Pinning the schema that already keeps its spelling does not trigger this diagnostic: that
schema was never going to move, so the pin asks for nothing generation was not already doing.

**A pin is a decision, so it is never renamed over.** Where the schema generation would otherwise
RENAME got its name from `models.<M>.name.csharp`, the C# target is refused instead: renaming over
an explicit pin would give you a type name you did not ask for. Give one of the two a different C#
name, or rename one schema everywhere with a [`rename_schema` transform](/docs/transforms#rename_schema).
Every other target still generates.
### Two of your own schemas sharing one name

Every code above is about a collision with something *Glotto* declares. This one is not: it fires
when two schemas **you** wrote would emit the same type, so neither name is reserved and there is
nothing of ours in the way.

| Code | Language | Fires when | Resolved automatically? |
| --- | --- | --- | --- |
| `GLOTTO_PHP_MODEL_NAME_COLLISION` | PHP | Two schema names emit one PHP class — `foo_bar`, `fooBar`, `foo-bar` and `FooBar` all emit `class FooBar`, and PHP class names are case-insensitive, so `widget` and `WIDGET` are one class too | Yes — the later ones become `FooBarModel`, `FooBarModel2`, … and every rename is reported. You only see the diagnostic if the rename cannot be applied |

PHP gives every model its own file, so before the rename existed the second schema's file simply
replaced the first on disk and the model was gone — with `php -l` reporting the survivor clean, the
SDK loading without complaint, and its own test suite passing. That is the failure the automatic
rename removes.

Two situations still stop the PHP target rather than renaming, and both raise the code above. The
first is a **pin you cannot have**: if you set `models: { A: { name: { php: FooBar } } }` while
another of your schemas already emits `FooBar`, generation refuses instead of quietly giving your
pinned model a different name — a pin is a decision, not a suggestion. Rename either schema, or drop
the pin and let the automatic rename resolve it. The second is a collision the rename does not yet
cover — a schema named after a **discriminated-union variant class**, such as `PetCat` for a `Pet`
union with a `cat` discriminator value. Generation stops and names both files rather than writing an
SDK with one of the declarations deleted out of it; renaming the schema resolves it.
### When two of *your own* schemas collide

Everything above is a schema colliding with a name the SDK itself puts in scope. Two of *your own*
schemas can collide the same way, and Glotto resolves that by renaming too — the second schema keeps
its data, its fields and its file, under a `<Name>Model` type name that the generate run reports.
Nothing is dropped, and no target is skipped.

There is one case it cannot resolve for you: when you **pinned** the name it would have to move.

| Code | Language | Raised when | How to resolve it |
| --- | --- | --- | --- |
| `GLOTTO_RUBY_MODEL_NAME_COLLISION` | Ruby | You set `models.<model>.name.ruby` to a Ruby name another of your schemas already emits. Ruby's constant and file-name casing merge spellings your spec keeps apart — `FooBar`, `foo_bar`, `fooBar` and `foo-bar` all emit `Glotto::FooBar` into `lib/glotto/foo_bar.rb`, and `foofoo` / `FOOfoo` share the file while `FOOFoo` / `FOO_foo` share the constant, so two names that look distinct to you can be one name to Ruby | Rename either schema: pick a different Ruby name for the pinned one with `models.<model>.name.ruby`, or give the other schema a Ruby name of its own the same way. Removing the pin also resolves it — without one the collision is renamed automatically. Only the Ruby target is affected; every other SDK in the same run still generates |
| `GLOTTO_RUBY_UNIT_CONSTANT_COLLISION` | Ruby | Two files of the generated Ruby gem would declare the same constant at the top of the `Glotto` module — for example a schema whose name lands on one of the SDK’s own classes after the automatic rename has already run. Ruby does not refuse a repeated constant: it reopens the first declaration and MERGES the second into it, so the gem would load, the generated tests would pass, and the class would be half your schema and half the SDK’s. Generation stops instead | Rename the schema that collides with `models.<model>.name.ruby`, choosing a name no other schema and none of the SDK’s own classes use. The message names both files, so the second path tells you which of your schemas is involved. Only the Ruby target is affected; every other SDK in the same run still generates |

A pin is treated as a decision rather than a suggestion, which is why this is reported instead of
renamed: quietly emitting your pinned schema under a different name would substitute a type name you
never asked for. A pin on the schema that *keeps* its name is never reported — that one generates
exactly as you pinned it.
## Two generated Kotlin types that claim one file

| Code | Meaning |
| --- | --- |
| `GLOTTO_KOTLIN_EMITTED_PATH_COLLISION` | Two types the Kotlin SDK generates **from your spec** would be written to the same file, and neither of them is a schema, so there is no model for the automatic rename above to move. The message names both keys that produced it. Two cases you can actually hit. (1) An operation with an inline JSON or multipart request body mints `<Resource><Method>Request`, and a discriminated union mints `<Union><Value>` from your own discriminator values — so a `pets.add` operation beside a union named `PetsAdd` that maps the value `request` both mint `PetsAddRequest`. (2) Two of your keys that differ only in CASE mint two type names that differ only in case — resources keyed `widget` and `WIDGET`, each with an inline request body, mint `WidgetAddRequest` and `WIDGETAddRequest`, and a JVM class file is named after the type rather than the source file, so the two claim one `.class` path however the sources are named. Rename the union, the discriminator value, the resource, or the operation; any one of the four resolves it. Only the Kotlin target drops out — every other target you configured still generates. |

Kotlin is the one language where two generated types can claim one file *without* a schema being
involved, because it writes one file per top-level type and names each file after the type. The same
property is why the Kotlin reserved set above compares the SDK's **own** type names
case-insensitively while leaving `List`, `Map` and `Any` alone: `Client` and `CLIENT` are two
perfectly good Kotlin types, but they compile to `Client.class` and `CLIENT.class`, which are one
file on macOS and Windows. That build is **green** and the class is simply absent, so a schema named
`CLIENT` is renamed to `CLIENTModel` rather than left for a compiler that will not complain.
A separate problem with a separate code, and no name of the SDK's involved. Java writes each model
to its own `com/glotto/<Name>.java` and derives that name in PascalCase, which is lossy — so two
schemas that differ only in casing or separators (`widget` and `Widget`, `foo_bar` and `FooBar`)
emit **one** type name and claim one file. Left alone, whichever file is written last destroys the
other, the SDK builds cleanly, and one of your schemas is simply not in it.

| Code | Language | When you see it |
| --- | --- | --- |
| `GLOTTO_JAVA_MODEL_NAME_COLLISION` | Java | Two or more of your schemas emit the same Java type name, **and** you pinned the one Glotto would have renamed with `models: { … : { name: { java: … } } }` |

**Generation resolves this for you when you have not pinned a name.** The schema whose name is
already spelled exactly as the type it emits keeps that type name, and each other takes the model
suffix — `FooBar` and `fooBar` become `FooBar` and `FooBarModel`. Where no schema is spelled that
way, the first key in code-point order keeps it — and generation reports every rename it applied, exactly as it does for a
[reserved model name](#reserved-model-names). The order your schemas appear in your document never
decides this, so re-ordering two of them never moves a type name. Only the named target's type name
changes; your other SDKs keep both original names.

**A pin is a decision, so it is never renamed over.** Where the schema the rename would have moved
got its name from `models.<M>.name.<target>`, that one target is refused instead: renaming over an
explicit pin would give you a type name you did not ask for. Give one of the two a different name
for that target, or rename one schema everywhere with a
[`rename_schema` transform](/docs/transforms#rename_schema). Every other target still generates.

### The same collision in every other target

The rule above is not C#'s, Java's, PHP's or Ruby's — it is one rule, and every target Glotto
generates applies it. Six more raise their own code for the pinned case:

| Code | Language | What the collision would have done, measured |
| --- | --- | --- |
| `GLOTTO_DART_MODEL_NAME_COLLISION` | Dart | `dart analyze` reports `The name 'FooBar' is already defined` and the SDK does not analyze |
| `GLOTTO_ELIXIR_MODEL_NAME_COLLISION` | Elixir | **Nothing at all.** `elixirc` exits 0 with no diagnostic and the second `defmodule` simply replaces the first, so one of your schemas is gone from a build that reported success |
| `GLOTTO_GO_MODEL_NAME_COLLISION` | Go | `go vet` reports `FooBar redeclared in this block` and the SDK does not build |
| `GLOTTO_PYTHON_MODEL_NAME_COLLISION` | Python | **Nothing at all.** Importing the SDK succeeds and the second `class` rebinds the name, so one of your schemas is gone with no error from any tool |
| `GLOTTO_RUST_MODEL_NAME_COLLISION` | Rust | `cargo check` reports `error[E0428]: the name \`FooBar\` is defined multiple times` and the SDK does not build |
| `GLOTTO_SWIFT_MODEL_NAME_COLLISION` | Swift | `swiftc` reports `invalid redeclaration of 'FooBar'` and every use site becomes ambiguous, so the SDK does not build |
| `GLOTTO_KOTLIN_MODEL_NAME_COLLISION` | Kotlin | `kotlinc` writes one file per top-level type, so the two claim one path and one is discarded before the compiler runs. Distinct from `GLOTTO_KOTLIN_EMITTED_PATH_COLLISION`, which is the case where neither name is a schema of yours |

**Two of those six say nothing, and that is the reason the rename exists.** In Elixir and Python the
generated SDK builds, imports, and passes its own emitted tests with one of your schemas missing —
there is no error to look for, and no exit code that would tell you. The four that fail loudly are
the easy half.

Everything in the two paragraphs above applies unchanged to all of them: the collision is renamed
automatically and every rename is reported, only the affected target's type name moves, and a pin is
refused rather than renamed over.

## The spec-repo target

Raised when [`targets.spec_repo`](/docs/spec-repo) asks for a document your input cannot produce.
Both are refusals of an **input domain**, not of postponed work — and both stop the run rather than
publishing a spec repo with a document missing, because a published spec repo is a surface your
consumers read: an absent file there reads as a fact about your API rather than as a Glotto refusal.

| Code | Meaning |
| --- | --- |
| `GLOTTO_SPEC_REPO_INPUT_UNSUPPORTED` | The target is enabled for an input that has no spec document to publish. A GraphQL input is the case: it never becomes a canonical spec document, which is the same reason no spec changelog is produced for it. Remove `spec_repo` from `targets:`, or point the project at an OpenAPI or AsyncAPI spec. |
| `GLOTTO_SPEC_REPO_VARIANT_UNAVAILABLE` | One requested variant cannot be produced for this input; the message names which and why. `with_code_samples` needs `openapi.code_samples.formats` set (and is OpenAPI-only); `with_transforms` is OpenAPI-only, because the transform engine never runs on an AsyncAPI document. Drop that member from `targets.spec_repo.variants` — the remaining variants publish normally. Distinct from the code above so you can tell "your spec cannot be published" from "two of the three documents you asked for can". |

## Retiring a file Glotto no longer generates

Raised when a Glotto release stops emitting a file your project already has — a build config the
stack outgrew, a module a newer layout replaced. Regeneration removes it, so your tree keeps
matching the project Glotto builds today rather than accumulating files nothing reads.

**Only a file Glotto can prove it wrote is ever removed**, and only while your copy still matches
the bytes Glotto produced. Every generated source carries a `@glotto:generated-checksum` comment;
that comment is what makes the removal safe. A file with no checksum comment — anything you added
yourself, and anything Glotto emits unstamped, such as the machine-readable mirrors under
`public/` — is left exactly where it is, whether or not Glotto still generates it. Turning a target
off in `glotto.yml` deletes nothing either: the tree it wrote stays until you remove it.

That leaves one case Glotto will not decide for you.

| Code | Meaning |
| --- | --- |
| `GLOTTO_RETIRED_FILE_EDITED` | Glotto no longer generates this file, **and you have edited it** since it was generated — so removing it would destroy work, and keeping it would leave your project carrying a file the current stack does not use. The run stops before writing anything, so your tree is untouched and every other file is exactly as you left it. Move whatever you still need into a file you own, then rerun. To retire it as-is, rerun with `--force`: Glotto copies the file to `.glotto/backup/` before removing it and names the copy in its summary, so the bytes stay recoverable either way. |
