Skip to content Documentation index for agents (llms.txt)
Glotto Beta
Get started

Diagnostics configuration

Tuning diagnostics

The ruleset above is the default. A diagnostics block in glotto.yml tunes it without touching the rules engine — it is a pure post-pass over the findings:

# glotto.yml
diagnostics:
  rules:
    no-error-response: error          # promote a warning to a release-blocking error
    mutation-no-idempotency-key: off  # suppress a rule entirely
  max_warnings: 10                    # fail (exit 1) when warnings exceed this budget
  • diagnostics.rules maps a rule id to a severity override — off suppresses the rule, while warn / error remap its severity. Promoting a warning to error makes it release-blocking; setting a rule to off drops its findings (and they no longer count toward max_warnings). An unknown rule id is almost certainly a typo, so it’s reported as a non-fatal warning on stderr and otherwise ignored.
  • diagnostics.max_warnings is a release-gating threshold: after overrides are applied, the remaining warning count exceeding this number fails the gate — even with zero errors. Start loose and ratchet it toward 0 as you approach 1.0 (see Release-gating guidance).

Both keys are optional and additive — a config with no diagnostics block lints exactly as the defaults above.

The valid rule ids are the ones enumerated on this page, plus two that tune a config diagnostic rather than a spec rule:

  • config-entry-matched-nothing — the severity of GLOTTO_CONFIG_ENTRY_MATCHED_NOTHING (below). off silences it, error makes it blocking. It’s tunable because a keyed entry naming an operation your spec no longer carries is legal by design — a glotto.yml is meant to outlive a spec change — so a team deliberately carrying one can say so here instead of dropping --strict.
  • config-auth-scheme-inert — the severity of the two inert halves of GLOTTO_CONFIG_AUTH_SCHEME_REFUSED (below): a top-level client_settings.auth.header_prefix on an API whose security schemes cannot format one, and a client_settings.auth.schemes block on an API that declares a single security scheme. Both are the same kind of legal by design — a glotto.yml outliving a change to your spec’s auth shape — so one off-switch covers them. It deliberately does not cover the third half, a header_prefix on an apikey, basic or custom scheme: no spec change makes that field applicable to those kinds, so there is nothing deliberate to declare.

The two are independent switches: they say different things (“my config outlives my spec’s operations” versus “my config outlives my spec’s auth shape”), so silencing one leaves the other reporting. The remaining config warnings report a directive Glotto structurally declined, which has no legal-by-design reading, and aren’t overridable.

Config diagnostics

The rules above lint your OpenAPI spec. Problems in your glotto.yml are reported by a separate gate that validates the config against the schema, and it runs first — an invalid config stops the pipeline before any spec rule is evaluated. glotto generate reports these on stderr. Unlike the spec rules, they are keyed by a stable code and carry a source position (file:line:col) into your glotto.yml:

Code Severity Meaning
GLOTTO_CONFIG_REQUIRED_FIELD_MISSING error A required key is absent (e.g. organization.name).
GLOTTO_CONFIG_INVALID_TYPE error A value has the wrong type (e.g. a string where an object is expected).
GLOTTO_CONFIG_INVALID_ENUM_VALUE error A value is outside the allowed set (e.g. react_native.secure_storage, mcp.modes).
GLOTTO_CONFIG_INVALID_VALUE error A value fails a field-specific rule (e.g. max_delay < initial_delay; an operationId in both skip and only, or in both exclude and only).
GLOTTO_CONFIG_EXCLUDE_ONLY_CONTRADICTION error An exclude entry and an only key address the same operation using the two different spellings exclude accepts — e.g. exclude: ["post /pets"] alongside only: { createPet: … }. Contradictory intent, exactly as naming it the same way in both is: only restricts the operation to the listed targets, exclude withholds it from every artifact. exclude is applied first, so the operation is withheld everywhere and the only entry has no effect. Reported at generate time, where the spec is available to resolve the positional spelling.
GLOTTO_CONFIG_INPUT_SOURCE error Not exactly one of openapi / asyncapi / graphql is present.
GLOTTO_CONFIG_OPENAPI_SOURCE_NOT_FOUND error A local openapi.source path doesn’t resolve on disk.
GLOTTO_CONFIG_OPENAPI_COMMAND_OUTPUT_PATH error A command-source file output is absolute or escapes its working directory. Reported for a command source at any input site — openapi.source, asyncapi.source, graphql.source, graphql.operations, and each docs.versions[] snapshot — with the message naming the offending path; the code keeps its historical OPENAPI spelling so a config matching on it keeps working.
GLOTTO_CONFIG_INTROSPECT_SOURCE_OPENAPI_ONLY error An introspect source was written somewhere other than openapi.source. Introspection reads a framework’s source and synthesizes an OpenAPI document, so it cannot be what an asyncapi or graphql key means. Point the key at the document it describes, or move the introspect source to openapi.source.
GLOTTO_CONFIG_DEFAULT_ENVIRONMENT error default_environment names an environment that isn’t declared under environments. The message lists the names you did declare. This is an error rather than a fall-back-and-warn because there is no fallback that keeps what you meant: resolving it any other way would point your SDK, your docs playground and your MCP server at a host you wrote the key specifically to avoid. Fix the spelling, or add the environment.
GLOTTO_CONFIG_DEFAULT_ENVIRONMENT_INFERRED warning Your config declares two or more environments, none of them named production, and no default_environment — so Glotto used the first by sorted name, and the message says which. That rule exists so generated code never depends on the order you typed your YAML in; it is deliberately not a guess at which host you meant. Set default_environment to the one your SDKs, their README quickstarts, your docs playground and your MCP server should all point at. You will not see this for a single environment (nothing to choose between) or when one is named production (that one wins).
GLOTTO_CONFIG_DOCS_VERSIONS error A docs.versions entry has a non-route-safe slug, a duplicate slug, more than one default: true, or declares other than exactly one snapshot source (openapi / asyncapi / graphql). A slug is also rejected when the URL layer would rewrite it — the generated layout finds the current version by comparing the slug against a percent-encoded pathname segment, so a slug containing a space, a %, or a non-ASCII character never matches its own pages and every page under it silently falls back to the default version. Characters a URL path keeps verbatim (letters, digits, and -._~!$&'()*+,;=:@) are fine.
GLOTTO_CONFIG_DOCS_REDIRECTS warning A docs.redirects entry the generator will refuse to emit: an empty or non-string from/to, a from that is not site-absolute (it must start with /), a from or to containing whitespace (the emitted _redirects rule file is whitespace-delimited, so a host would read only the fragment before the space — percent-encode it), a from equal to its own to (a no-op loop), or a from an earlier entry already claims (the later one is unreachable). Also raised when your docs.deploy.target names a host whose own redirect config cannot express a from exactly — only a trailing * has an exact equivalent on Vercel, so an interior or repeated one is left out of the emitted vercel.json rather than rewritten into a rule that would match different URLs than you wrote. Only that entry is dropped — your other redirects still emit.
GLOTTO_CONFIG_DOCS_STRUCTURED_DATA warning A customer-authored docs.structured_data.extra_nodes / extra_nodes_by_route JSON-LD node the generator will refuse to carry: one that isn’t a JSON object, is an empty object, has no @type (a consumer dispatches on the type, so an untyped node is read by nothing), has a @type that isn’t a non-empty string — nor a non-empty array of them, JSON-LD’s multiple-type form — has an @id that isn’t a non-empty string or a @context that is neither a non-empty string nor an object, carries a nested @graph (that makes it a document rather than a node, and its members would be read as siblings of the derived ones), or exactly duplicates an earlier node in the same list. Only that node is dropped — your other nodes, and every node Glotto derives from your spec, still emit. This is a structural check: a misspelled @type, or a property that doesn’t belong to the type it sits on, is not validated here.
GLOTTO_CONFIG_DOCS_OG_TEMPLATE error A docs.og_images.template.colors value isn’t a colour the OG-card renderer can paint. Cards are rasterized by pureimage during your site’s astro build, not by a browser, so the accepted forms are #RGB / #RGBA / #RRGGBB / #RRGGBBAA, rgb(r,g,b) or rgba(r,g,b,a) with comma-separated numbers, and CSS named colours (rebeccapurple). hsl(), color(), gradients, var(--x), and the space-separated rgb(1 2 3) form are not supported — they either fail your build or paint a colour you didn’t ask for.
GLOTTO_CONFIG_DOCS_DEPLOY_DOMAIN error docs.deploy.custom_domain isn’t a bare DNS hostname. It becomes the authority of your docs site’s canonical URLs and the domain handed to your deploy provider’s binding, so write the hostname alone — docs.acme.com, not https://docs.acme.com, and no path, port, wildcard, or trailing dot. Labels are letters, digits, and hyphens, at most 63 characters each and 253 overall. Internationalized domains are supported in their punycode form (xn--caf-dma.example).
GLOTTO_CONFIG_MCP_PACKAGE_NAME error mcp.package_name isn’t a valid npm package name. It becomes the generated package.json "name" and — with any @scope/ stripped — the bin command name, so it must be at most 214 characters, lowercase, and made of letters, digits, and -._~, optionally with a single @scope/ prefix whose scope and name are each non-empty. Leave it unset to derive <your-org>-mcp instead.
GLOTTO_CONFIG_CODE_OWNERS error A code_owners rule the emission would have to guess about: a block that is declared but names no rules, a blank pattern, a rule with an empty owner list, an empty owner string, or an owner the forge your target’s repo lives on could not resolve. The message names the offending provider and the spellings it accepts — GitHub takes @login, @org/team-slug (exactly two segments) or an email address; GitLab additionally allows _ and . inside a segment and nests @group/subgroup/… without limit; Bitbucket and Azure Repos resolve an owner against your workspace directory, so anything non-empty is accepted here and checked when you apply it. This is an error rather than a dropped-and-warn because a CODEOWNERS line the forge cannot resolve is ignored in full — the path is left unowned, the file still exists, and nothing anywhere says so.
GLOTTO_CONFIG_CODE_OWNERS_NOT_APPLIED warning You declared code_owners, and this target does not receive a CODEOWNERS file. Two causes, both about the forge rather than your config. Bitbucket and Azure Repos read no such file — their equivalents are default reviewers and a required-reviewers branch policy, so Glotto applies the block through their APIs instead of emitting a file. A target with a repo_path lives in a subtree of a shared repo, and GitHub and GitLab read CODEOWNERS only from the repository root — a file emitted into the subtree would never be opened, so none is emitted; declare the ownership in the CODEOWNERS at that repository’s root instead. Reported by glotto generate.
GLOTTO_CONFIG_DOCS_AUTH error A docs.auth block omits a field its tier requires — password needs secret_env, sso needs both provider and login_url — or sets a non-positive session_hours. Supply the missing field (or drop the block to leave the docs site public).
GLOTTO_CONFIG_DOCS_AUDIENCES error A docs.audiences block names an audience in scopes or default that isn’t declared in members, or its members list is empty or has duplicates. Declare every audience in members first, and make default one of them.
GLOTTO_CONFIG_DOCS_PERSONALIZATION error A docs.personalization block has an empty fields allow-list, or a prefill_key_field that isn’t one of fields. Only fields on the allow-list are ever rendered into a page, so the key field has to be among them.
GLOTTO_CONFIG_DOCS_I18N error A docs.i18n block has a locale token that isn’t route-safe, a locales list that is empty or has duplicates, or a locales list that omits default_locale. Every locale becomes a URL segment, and the default has to be one of the locales you build.
GLOTTO_CONFIG_CUSTOM_CASINGS error A custom_casings key is not a lowercase alphanumeric word (identifier words are lowercased before matching, so API: API could never match — write api: API), or its rendering is not a pure re-casing of the key. Only letter case may differ; to change the word itself use naming (model members) or parameter_naming (method parameters).
GLOTTO_CONFIG_RENAME_NOT_APPLIED warning A naming member-rename targets an engine that doesn’t apply member renames — TypeScript and React Native (their DTOs are transparent, so the interface is the wire shape) or Python in the default non-pydantic mode — or an enums nominal-shaping directive targets an engine with no type-alias construct. The directive is accepted but the emitted member keeps its wire name. Drop it for that target, or use parameter_naming, which those engines do honor.
GLOTTO_CONFIG_NAMESPACE_NOT_APPLIED warning A targets.<slug>.namespace is set on one of the four SDKs whose published package name is its code identity — TypeScript and React Native (the npm package is the module you import), Dart (the pub package is the library you import), and Swift (the SwiftPM package is the module you import). There is no second name underneath it for namespace to set, so the key has no effect and the SDK keeps the identity package_name gives it. Set package_name for that target instead — for these four it is the code identity, and it also stays the name you publish under. namespace is honored for csharp, elixir, go, java, kotlin, php, python, ruby, and rust, where the two identities are genuinely separate (the Python import package vs. the PyPI distribution name; the Rust [lib] name vs. Cargo’s [package] name).
GLOTTO_CONFIG_CASING_NOT_APPLIED warning custom_casings is applied to model members, method parameters, and enum constants, but not yet to method names, class/type names, or resource accessors — those keep their default casing. Informational: no config change resolves it, and the warning clears when the remaining surfaces land.
GLOTTO_SPEC_UNION_DEGRADED warning A discriminated union won’t generate as a narrowed union (ADR-0041 eligibility); the SDK falls back to an open type.
GLOTTO_CONFIG_MODEL_SHAPING_REFUSED warning A models directive was declined — a rename onto a name another model holds, or an inline: true on a self-referencing model or a union member. The model stays as it was.
GLOTTO_CONFIG_AUTH_SCHEME_REFUSED warning A client_settings.auth directive was declined. Either a header_prefix was set on a scheme whose kind cannot carry one (apikey, basic, custom — only bearer and oauth2 format an Authorization value), or a top-level header_prefix was set on an API whose schemes are all of those kinds so it formats nothing, or a per-scheme schemes: block was written for an API that has a single security scheme, which is configured through client_settings.auth directly. A scheme name your spec no longer defines is not reported — a glotto.yml outlives a spec change. The last two are tunable with diagnostics.rules.config-auth-scheme-inert; the kind mismatch is not, because no spec change makes that field applicable.
GLOTTO_CONFIG_MODEL_RENAMED warning One of your models emits under a different type name for one target, because the name it would otherwise take is one that target’s own generated SDK source refers to — a schema named Data in a Swift SDK would land in the same module as the client’s own Data references and take them over, and Swift has no import-qualification escape for a same-module declaration. The generated name appends the target’s model suffix, and adds a number if that is taken too: DataDataModelDataModel2. Nothing is missing from the output and every reference to the model follows the new name; only the named target is renamed, so your other SDKs are unaffected. To pick the name yourself, set the key the warning opens with — a name.<target> entry under models. An explicit name is always honored and this warning stops. The key it names is the one you wrote, even when another models entry has already renamed that model, so it is always one your glotto.yml can carry.
GLOTTO_CONFIG_SOFT_REQUIRED_SPLIT warning A soft_required body_fields promotion generated a <Model>Request variant, because the operation’s request body is a model your API also returns — demanding the field on it would make it mandatory when decoding a response too. The shared model is unchanged; only this operation’s body uses the variant.
GLOTTO_CONFIG_AUTO_POPULATE_REFUSED warning An auto_populate position was declined — its schema doesn’t permit exactly one value, its one value has no sendable wire form, or the request body isn’t a JSON object. The input stays in the method signature. All four parameter locations (path, query, header, cookie) are supported.
GLOTTO_CONFIG_DUAL_MODE_REFUSED warning A streaming.dual_mode entry was declined, so the endpoint was not split into buffered and streaming methods — the operation isn’t in your spec, the spec never marks it as streaming, it takes no JSON-object request body, param_discriminator names a field that body doesn’t have, stream_event_model names a model your spec doesn’t define, the per-event type couldn’t be resolved (name it with stream_event_model), or the variant’s method name is already taken by a real operation (pick a different method_suffix). The operation keeps the single method it had.
GLOTTO_CONFIG_ENTRY_MATCHED_NOTHING warning An entry in one of the six operationId-keyed blocks — skip, only, exclude, parameter_naming, client_methods, aliases — names an operation your spec doesn’t carry, so it had no effect. Usually a typo; sometimes an operation renamed upstream since the config was written. The entry is still ignored rather than rejected (a glotto.yml outlives a spec change), so this is a warning you can tune or silence with diagnostics.rules.config-entry-matched-nothing.
GLOTTO_CONFIG_POSITIONAL_PARAMS_REFUSED warning A positional_params entry was declined — it names a parameter the operation doesn’t have, lists one twice, or places the $body token where it can’t be honored (the operation has no body, the body isn’t positional, taking it positionally would drag query parameters along, an optional body would precede a path parameter, or the token collides with a reserved name). The order is refused whole, so the method keeps its derived argument order — a partly-applied order would be a signature you never reviewed.
GLOTTO_CONFIG_RESOURCE_METHOD_NAME error A resources.<r>.methods.<key> declaration of the emitted method name could not be honored, so glotto generate stops. Either the endpoint beside it matches no operation in your spec (the verb and path must match exactly, placeholder names included — when exactly one operation serves the same route under a different placeholder name, get /pets/{id} against paths: /pets/{petId}, the message names the spelling your spec uses, which is usually a one-character fix), or the name it declares is already emitted by another operation on the same resource — in which case both operations are named and neither is renamed. Not suppressible: the alternative to stopping is shipping an SDK whose method names are not the ones you asked for, and a refused declaration would otherwise look exactly like one you never wrote.
GLOTTO_SPEC_README_UNKNOWN_OPERATION warning A readme.example_requests slot names an operation that is not an operationId in your spec. The README example falls back to the default selection. Usually a typo, or an operation renamed upstream.
GLOTTO_SPEC_README_UNKNOWN_PARAM warning A readme.example_requests.<slot>.params key matches no wire parameter of the operation it names — neither a path/query parameter nor a request-body field. The key is omitted from the rendered example.
GLOTTO_CONFIG_UNKNOWN_TARGET error A targets entry names no codegen engine, so glotto generate would refuse the config. The message lists the engines that exist. The usual cause is an emitted artifact that is not a target: mcp, docs and mock are configured by a top-level block of that name — see the MCP server guide — and the message says so for those three. Publishing is a different surface from the codegen targets: map: Glotto publishes the generated MCP server to npm for you, and that surface does accept mcp where targets: does not.
GLOTTO_SPEC_README_SLOT_KIND_MISMATCH warning A readme.example_requests pagination or streaming slot names an operation of the wrong kind (a non-paginated operation in the pagination slot, a non-streaming one in the streaming slot). That example falls back to the default selection.

A config error blocks generation; the warnings don’t, but a strict gate turns them (and any warning) into a non-zero exit — as does setting config-entry-matched-nothing: error, the one severity you can raise on its own. Every warning below GLOTTO_SPEC_UNION_DEGRADED is computed from your spec rather than from the config text, so they name the config path (models.Address.name, soft_required.updateInvoice.body_fields.note, parameter_naming.createPett) instead of a file:line:col position, and glotto generate prints all of them on stderr as well — you don’t need a separate validate run to see a directive that didn’t take. See the glotto.yml reference for the configuration surface itself.