Skip to content

opencode2: user-defined local provider models never enter the model catalog #42856

Description

@hirak99

Description

Summary

I downloaded opencode2 beta.

My user-defined local OpenAI-compatible provider (per the documented "Local models" config) is not visible, while it is working with opencode.

According to the model which investigated, it is parsed by the service but its model is never exposed in the catalog. opencode2 run -m <provider>/<model> fails with Model unavailable and the provider is absent from /api/provider.

Plugins

none

OpenCode version

opencode2 v0.0.0-next-17444 (channel: next)

Steps to reproduce

Steps to reproduce

  1. Create ~/.config/opencode/opencode.jsonc (also reproducible as a real file, non-symlink):
    {
      "$schema": "https://opencode.ai/config.json",
      "providers": {
        "local-llama-cpp": {
          "name": "Local llama.cpp",
          "package": "aisdk:@ai-sdk/openai-compatible",
          "settings": { "baseURL": "http://localhost:11434/v1" },
          "models": {
            "local-llm": {
              "modelID": "local-llm",
              "capabilities": { "tools": true, "input": ["text"], "output": ["text"] },
              "limit": { "context": 114588, "output": 32768 }
            }
          }
        }
      }
    }
  2. opencode2 service restart
  3. opencode2 api get /api/provider — only the built-in opencode provider is listed; local-llama-cpp is absent.
  4. opencode2 api get /api/model — only the 7 built-in opencode models are present.
  5. opencode2 run -m local-llama-cpp/local-llm "hi" → Error: Model unavailable: local-llama-cpp/local-llm

Expected Behavior

Per the Local models documentation, the local-llama-cpp/local-llm model should appear in the model picker and be runnable.

Actual Behavior

The provider is parsed and held by the service (confirmed via /api/config), but it never enters the model catalog: absent from /api/provider and /api/model, and run reports Model unavailable.

Screenshot and/or share link

No response

Operating System

Linux z390v2 7.1.8-arch1-3 x86_64 GNU/Linux

Terminal

Konsole / tmux

Additional Context

  • Distinct from providers: custom openai-compatible providers hang or send to undefined/chat/completions #36834 (closed):

    • There the model resolves but the request hangs / sends to undefined/chat/completions; here the model never enters the catalog, so the failure is earlier (catalog build / model resolution).
    • Also its repro used the V1 npm/options shape, whereas this report uses the documented native package: "aisdk:@ai-sdk/openai-compatible" + settings.baseURL shape.
  • The provider uses aisdk:@ai-sdk/openai-compatible — the exact package the built-in opencode provider uses, so the package resolves.

  • The config is confirmed loaded by the service: opencode2 api get /api/config returns the document with providers.local-llama-cpp and the model. No normalization warnings are emitted for the native V2 config.

  • Reproduced with:

    • Minimal native V2 config (above) as a symlink AND as a real file — identical failure, so the dotfiles symlink is not the cause.
    • V1 provider/npm/options syntax (converted per the migration guide) — same failure.
  • The OpenAI-compatible endpoint itself works: curl localhost:11434/v1/chat/completions returns a valid completion.

Activity

  1. fedor2018 commented on Sep 27, 2026

    @fedor2018

    Still reproducible on 2.0.18 (desktop, Windows 11 x64), and the scope looks wider than config-declared providers — credential-connected catalog providers are affected too.

    Version

    This issue was filed against v0.0.0-next-17444; #51252 / #51285 report 2.0.16 / 2.0.15. I hit the same failure on 2.0.18 (desktop build, bundled resources/opencode-cli.exe, channel=latest), so it is still live on the current release.

    New: catalog providers connected via /connect are also affected

    The existing reports all describe a provider declared in the providers block of opencode.jsonc. That is not the only path that fails.

    I connected Google through the official /connect flow four separate times. Each time the credential was accepted and stored, and each time the provider failed to materialize:

    $ opencode auth list
    Google            Google 3                    stored
    Google            Google 2                    stored
    Google            Google                      stored
    Google            API key                     stored
    OpenRouter        OpenRouter                  stored
    OpenRouter        API key                     stored
    
    $ opencode run -m google/gemini-3.5-flash "hi"
    Error: Model unavailable: google/gemini-3.5-flash
    
    $ opencode run -m openrouter/google/gemini-2.5-flash "hi"
    Error: Model unavailable: openrouter/google/gemini-2.5-flash
    

    Note that openrouter is a pure catalog provider with no config entry at all — only a stored credential — and it fails the same way. So the defect is not limited to the config → registry path described here; the credential → activation path is broken too.

    The integration catalog layer works; only activation is missing

    This is the part that looks like a clean layer boundary:

    GET /api/integration          -> 227 integrations, including `google`
    GET /api/integration/google   -> methods: [key, env(GOOGLE_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY,
                                                GEMINI_API_KEY)]
                                     connections: 4 stored key credentials
    GET /api/provider             -> opencode          (only entry)
    GET /api/model                -> 7 opencode/* console models
    

    google is fully known, its connect methods resolve, and its credentials are present — but it never reaches the provider registry.

    Ruled out

    • Credential validity — the Google key was verified directly against https://generativelanguage.googleapis.com/v1beta/models: HTTP 200, 50 models returned.
    • Catalog availability — https://models.dev/api.json is reachable; its google entry contains 40 models.
    • Config parsing — opencode debug config shows the config read and V1 keys correctly normalized to V2.
    • Env-based activation — opencode service set env GOOGLE_API_KEY <key> does not activate it.
    • Explicit provider definition — package: "@opencode/ai/providers/google" plus an explicit models map (to bypass the catalog entirely) is accepted, fires config.updated / provider.updated, and still does not materialize.
    • Stale service — full stop + start changes nothing; credentials survive and the result is identical.
    • Config content — removing the only custom provider entirely, leaving a config that declares nothing but $schema, and restarting still yields only the console provider.

    No error is logged

    Immediately after a Google credential is created, the log contains only:

    06:33:26  credential created  integrationID=google type=key
    06:34:24  event.type=provider.updated
    06:34:24  event.type=model.updated
    

    google never appears, and there is no warning or error anywhere in ~/.local/share/opencode/log/opencode.log explaining why. Reproducibility is 100% across restarts, both directory scopes, and every activation method available.

    If context.provider.reload() is the intended escape hatch (as #51285 asks), I would be happy to test it — but note that reload() would only help the config-declared case, since /connect-based catalog providers never materialize in the first place.

  2. wangjianjq commented on Oct 1, 2026

    @wangjianjq

    Cross-referencing: this also reproduces on the stable channel, not just next — verified on CLI 2.0.15 / 2.0.20 / 2.0.21 (Windows 11, standalone and desktop service) with both legacy provider/npm/options and new providers/package/settings syntax. Full repro and version matrix posted in #51285 (comment) — same signature: config parses and normalizes cleanly, never materializes into the registry, -m provider/model → ModelUnavailableError, silent fallback to a built-in opencode/* model when no -m is given.

    One extra data point: with no -m, the configured default custom model is silently ignored (falls back to the built-in catalog), which makes the breakage easy to miss.

  3. StandarterDF commented on Oct 8, 2026

    @StandarterDF

    Confirming this on OpenCode 2.0.24 (Windows 10 22H2, x64, @opencode/cli, npm latest).

    A providers entry with a non-catalog id is parsed (it shows in GET /api/config) but never reaches GET /api/provider or GET /api/model, so opencode run --model <id>/<model> fails with Model unavailable. Reproduced with the docs' "Custom" recipe (package: @opencode/ai/providers/openai-compatible + settings.baseURL + one model). Adding/overriding a model on a catalog provider (e.g. under opencode) via providers does work, so the break is specifically materializing new provider ids.

    From a plugin, ctx.provider.transform -> editor.add({ info, models }) registers the provider (it shows up in ctx.provider.list() / ctx.model.list()) but it never becomes available either — same as #51802. Tried with an integrationID of an existing integration plus an active key credential, with sourceConnection, and with canonical; none helped. Built-in local discovery (LM Studio GET /api/v1/models on 127.0.0.1:1234, vLLM GET /health + /v1/models on 127.0.0.1:8000) also issues requests but does not activate a provider.

    Workaround that works (used to make a local llama.cpp / llama-swap server usable on 2.0.24): attach the local models to the already-active opencode provider as alias models, with a catalog modelID (so the model is materialized), model-level settings.baseURL pointing at the local server, and body.model overriding the upstream model name:

    {
      "providers": {
        "opencode": {
          "models": {
            "local-gemma": {
              "modelID": "big-pickle",
              "settings": { "baseURL": "http://127.0.0.1:9932/v1" },
              "body": { "model": "gemma4-26a4b-styletune-rp" },
              "limit": { "context": 65536, "output": 8192 },
              "capabilities": { "tools": true, "input": ["text"], "output": ["text"] }
            }
          }
        }
      }
    }

    opencode run --model opencode/local-gemma "…" then reaches the local server. The same works from a plugin via ctx.model.transform -> editor.update("opencode", alias, draft => { draft.modelID = "big-pickle"; draft.settings = { baseURL }; draft.body = { model }; draft.limit = …; draft.capabilities = … }).

    Full details in #53912.

  4. ashleysommer commented on Oct 11, 2026

    @ashleysommer

    Confirming, seeing the same bug still on v2.0.26

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions