1jehuang / 1jehuang/jcode

Bug: OpenRouter @provider pin silently lost — routes to wrong backend (e.g. Alibaba instead of Novita)

Open
#736 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

autonomous: no bug priority: high triage: needs-decision triage: reproducible
Dominant language
Rust
Stars
19.9k
Forks
2.3k
Avg merge
2d 7h
Merged PRs (30d)
30

Description

Bug: OpenRouter @provider pin silently lost — routes to wrong backend (e.g. Alibaba instead of Novita)

Summary

When using /model z-ai/glm-5.2@Novita, jcode silently routes to a different OpenRouter backend provider (e.g. Alibaba) instead of the user's pinned choice. The @provider pin is lost in multiple code paths, and the default allow_fallbacks=true lets OpenRouter fall back to whatever provider it ranks first.

Reproduction
  1. Have OPENROUTER_API_KEY configured
  2. Start jcode
  3. Run /model z-ai/glm-5.2@Novita
  4. Send a message
  5. Check the session header — it shows via Alibaba instead of via Novita
Root Cause (confirmed via runtime logs)

Four bugs combine:

  1. OpenRouterProvider::fork() resets provider_pin to None instead of copying from the parent. Forked providers lose the pin entirely.

  2. provider.model() returns the bare model id (z-ai/glm-5.2) without the @Novita pin. Session save/restore paths all used provider.model(), so sessions restored without the pin. OpenRouter then used endpoint ranking, Alibaba served first, and the observed session pin locked onto Alibaba with allow_fallbacks=false.

  3. handle_auth_changed replaces the OpenRouter runtime with a fresh one (losing the pin) when reconcile_auth_if_provider_missing triggers on_auth_changed().

  4. Explicit @provider pins allowed fallbacks by default@Novita (without !) set allow_fallbacks=true, so OpenRouter could fall back to a different provider. Once Alibaba served a request, it got observed-pinned and locked the session.

Log evidence
# First request: no pin, endpoint ranking (Alibaba first)
OpenRouter routing: model=z-ai/glm-5.2, order=Some(["CoreWeave", "Cloudflare", ..., "Alibaba", ..., "Novita", ...]), allow_fallbacks=true

# Subsequent requests: locked to Alibaba via observed pin
OpenRouter routing: model=z-ai/glm-5.2, order=Some(["Alibaba"]), allow_fallbacks=false
Fix

A fix is available on my fork: https://github.com/ewheels44/ecode/pull/1

Branch: fix/openrouter-provider-pin (3 commits, cherry-picked clean from upstream/master)

Changes:

  • OpenRouterProvider::fork() now copies provider_pin from parent
  • Added explicit_provider_pin_for_current_model() on MultiProvider to reconstruct full model@pin spec
  • All session save/restore paths use provider_model() which includes the pin
  • handle_auth_changed re-applies model+pin when replacing the OpenRouter runtime
  • Explicit @provider pins now always set allow_fallbacks=false

After fix:

OpenRouter routing: model=z-ai/glm-5.2, order=Some(["Novita"]), allow_fallbacks=false
Environment
  • jcode v0.61.14-dev
  • macOS aarch64
  • OpenRouter API key configured
  • Affects all OpenRouter models with @provider syntax

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with OpenRouterProvider::fork(), MultiProvider::explicit_provider_pin_for_current_model(), the session save/restore paths, and handle_auth_changed. Compare the behavior with the fix described on the linked fork, then verify that an explicit @provider request remains pinned through forking, persistence, and authentication changes, with fallbacks disabled.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.