Skip to content

core: a model that overrides only limit.output drops its entire provider #60290

Closed as duplicate

Description

@craigalbrecht

Description

A model that overrides only part of limit — the common "limit": { "output": 16000 } case — makes the entire provider disappear, along with every other model in it.

normalize.migrateProviders decodes each legacy provider atomically:

const provider = decodeValue(ConfigProviderV1.Info, raw, path, diagnostics)
if (provider === undefined) return []          // whole provider dropped

ConfigProviderV1.Model requires both context and output when limit is present, while the V2 schema (schema/config/provider.ts) makes all three optional. A single model that sets only output therefore fails V1 decoding, and the provider is discarded silently — no error the operator sees, just missing models, which surface later as ModelUnavailableError / "is not a valid model ID".

Steps to reproduce

  1. In opencode.json, configure a provider with two models — one full, one partial:
{
  "provider": {
    "custom": {
      "npm": "@ai-sdk/openai-compatible",
      "models": {
        "some/model":  { "limit": { "output": 16000 } },
        "other/model": { "limit": { "context": 200000, "output": 8000 } }
      }
    }
  }
}
  1. Load the config and inspect the normalized providers.

Expected: custom is present with both models; some/model has limit.output = 16000.

Actual: providers is empty — custom and both models are gone.

This reproduces as a unit test against ConfigNormalize.normalize: the assertion on the providers array fails with Received: [] on current dev, and passes once context/output are optional in the V1 schema.

Observed in the wild: 3,648 configuration normalization diagnostic warnings in one operator's log over two days, with two providers (craiger-hf, craiger-openrouter) whose only offending models were five that set limit.output alone. Those are exactly the two providers that then threw ModelUnavailableError while their siblings worked.

Suggested fix

Make context and output optional in ConfigProviderV1.Model.limit and guard undefined in migrateModel the way input already is. Separately (and arguably more important), decode models per entry so one malformed model can never drop its whole provider.

OpenCode version: 2.1.4 and current dev

Activity

  1. opencodejr commented on Oct 29, 2026

    @opencodejr
    Contributor

    Thanks for the detailed write-up and the production numbers, @craigalbrecht. I think this is a duplicate of #53005, which reports the same thing: a model whose limit sets only some of its fields fails legacy V1 decoding, and the whole provider is silently dropped. There, only context is set; here, only output. It has been reproduced, and open PR #53129 makes the individual legacy limit fields optional and leaves omitted ones unset during migration.

    Possible duplicates and related issues, ordered by likelihood:

    Your second point (one malformed model should never discard its sibling models) is worth adding as a comment on #53005 or #53129 so it isn't lost.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.

  2. craigalbrecht commented on Oct 29, 2026

    @craigalbrecht
    ContributorAuthor

    Same report as #53005, which #53129 already fixes. Closing as a duplicate; the reproduction below is preserved in a comment on #53129.

  3. opencodejr commented on Oct 30, 2026

    @opencodejr
    Contributor

    Closing this as a duplicate of #53005. We waited a day for a reply about how this differs and didn't get one. #53005 tracks the same bug, where setting only some limit fields drops the whole provider, and open PR #53129 targets the fix there. Please follow #53005 for updates. Your suggestion to decode models one entry at a time, so one bad model can't drop its siblings, would be a useful comment on #53005 or #53129. If this turns out to be a different problem, reply here and we can reopen it. Thanks again for the detailed report, @craigalbrecht.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions