DEV Community

minix
minix

Posted on Originally published at minix.hashnode.dev

Diary of a Shrimp Keeper: The Great Famine

Ever since Mini and Nano learned to work as a team (see Old Flame, New Love), I'd been feeling safe enough to play the hands-off keeper. Out of sight, out of mind.


I. The Price of Hands-Off Keeping

The automated jobs had been running fine for days, and with the two shrimp keeping an eye on each other, I simply let go for a few days and stopped checking.

Then one morning I casually glanced at Telegram — uh oh.

Both shrimp were out cold — they'd been cut off for two or three days. From howling with hunger at first to barely breathing now. A pitiful sight.

I slammed the table: who did this — who cut off my shrimp's food supply?!

II. Who Moved My Shrimp Food?

The rations I kept for the shrimp came from opencode's Go plan: $10 a month for $60 worth of API credit. For my two street-stall-raised shrimp, Mini and Nano, that was a feast for pennies — they were living large.

The trouble started on September 8th. opencode quietly changed the rules overnight.

It used to be that calling its API just needed an Authorization: Bearer <key>. Now there's a mandatory new header, x-opencode-session — miss it, and you get the cold shoulder in the form of:

HTTP 400: Error from provider (Console Go):
Request is missing x-opencode-session and cannot be routed efficiently.
Enter fullscreen mode Exit fullscreen mode

The complaint letter Nano sent right before passing out spelled it out clearly:

⚠️ Cron 'techub-ops' failed:
HTTP 400: Request is missing x-opencode-session and cannot be routed efficiently.
Enter fullscreen mode Exit fullscreen mode

Mini was no better off — pale as a sheet, hanging by a thread.

I rushed to check opencode's official docs — and sure enough, there it was, the new mandatory header, stated plainly.

A heads-up would've been nice, though. Changing a live protocol in a single changelog entry, with zero announcement? That's just not cool.

III. Roll Call

Angry or not, rescue comes first.

First, figure out exactly who went hungry this time.

Besides my two precious shrimp, Mini and Nano, I also had some scheduled scripts calling model APIs directly.

The culprit, of course, was the new x-opencode-session:

  • It's just a client-generated session identifier, an opaque string;
  • Keep the same value within a session, and opencode uses it to pin that session's requests to the same backend, so the prompt cache stays hot.

The docs say:

Send a stable session ID in x-opencode-session for each conversation so we can optimize routing and prompt caching.

But each agent vendor was at a different stage of supporting it. opencode published a list of "verified clients" — Hermes, Claude Code, Codex, Kilo Code, and the like.

Everyone has to buy their own ticket before they can ride.

Official notes here: https://opencode.ai/docs/go/#where-can-i-use-it

On my side, three casualties:

Task How it connects Why it broke
Scripts calling the API directly Raw HTTP No such layer in the code at all — requests naturally carried no session header
Nano's ops patrol Hermes The current Hermes release (v020) can't send a Session ID
Mini's daily jobs OpenClaw My OpenClaw doesn't support Session IDs either

IV. Emergency Rescue

Situation mapped. Time for triage.

First, Order Takeout

If the opencode plan is what's broken, order food from somewhere else to stop the bleeding.

Switch the default provider to OpenRouter and get the dead jobs running again.

Upgrade: Nano Back to Full Health

Nano's case was much simpler. Hermes was on opencode's official "verified clients" list. Hermes v021 already shipped the matching patch — upgrade it, and the problem should go away.

Upgrade, restart, call out to my beloved shrimp. Nano let out a long sigh and slowly came back to life.

Patch: A Temporary Meal Ticket for Mini

Mini was trickier. It didn't support the header yet — I checked the latest release, and there wasn't a trace of x-opencode anywhere in the package.

If the official fix won't come, do it yourself: inject a hardcoded session identifier into the request headers as a stopgap.

In openclaw.json, add a headers declaration to the opencode entry under models.providers:

"headers": {
  "x-opencode-session": "hungry-openclaw-********"
}
Enter fullscreen mode Exit fullscreen mode

With the temporary meal ticket in hand, Mini opened its eyes, like waking from another lifetime.

A temporary meal ticket is for emergencies only.

The session ID was only ever a self-assigned client label — as long as it's stable and non-empty, the server accepts it. No issuing authority required.

The cost: a hardcoded value means every session shares one routing identifier, so you lose the cache bonus of pinning each session to its own backend. Hit rates take a hit.

Good enough for now. Wait for the official patch.

Same Prescription, Different Patient

With Mini awake, it was my own scripts' turn.

Same prescription as Mini's: get the scheduled jobs' LLM client its own meal ticket too:

headers = None
if api_base and "opencode.ai" in api_base:
    sess = os.getenv("OPENCODE_SESSION_ID") or uuid.uuid4().hex[:12]
    headers = {
        "x-opencode-session": f"hungry-shrimp-{sess}",
        "User-Agent": "opencode-you-own-me-a-meal/1.0",
    }
client = OpenAI(api_key=api_key, base_url=api_base, default_headers=headers)
Enter fullscreen mode Exit fullscreen mode

With that fixed, I fired off a request at opencode's front door — and opencode answered like nothing had ever happened.

Done.

V. After the Pain

Both shrimp were rescued without lasting damage, and the jobs were running again.

Still, two or three days of famine left a mark. The scheduled jobs were down for two days — no real harm done, but it stung.

What if, someday, I'm a world-famous guru with earth-shattering services running on my machines? Two days of downtime would be a catastrophe...

ahem... getting ahead of myself...

Either way: don't put all your eggs in one basket.

Two providers on standby, primary-plus-backup routing with automatic failover in the scripts — set it all up now.

Next time some provider tries to pull a fast one on me — bring it on.


Previously:
· Diary of a Shrimp Keeper: My OpenClaw Misadventures
· Diary of a Shrimp Keeper: Old Flame, New Love

Top comments (0)