<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: lakshit gupta</title>
    <description>The latest articles on DEV Community by lakshit gupta (@lakshit_gupta).</description>
    <link>https://dev.to/lakshit_gupta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4100352%2F0a6b2ebe-d660-4634-87d2-59dfbeff5af6.png</url>
      <title>DEV Community: lakshit gupta</title>
      <link>https://dev.to/lakshit_gupta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lakshit_gupta"/>
    <language>en</language>
    <item>
      <title>I Wanted to Try Pi Instead of OpenCode. Then I Had to Debug a 500.</title>
      <dc:creator>lakshit gupta</dc:creator>
      <pubDate>Sat, 29 Aug 2026 13:59:31 +0000</pubDate>
      <link>https://dev.to/lakshit_gupta/i-wanted-to-try-pi-instead-of-opencode-then-i-had-to-debug-a-500-4cg3</link>
      <guid>https://dev.to/lakshit_gupta/i-wanted-to-try-pi-instead-of-opencode-then-i-had-to-debug-a-500-4cg3</guid>
      <description>&lt;p&gt;I wanted to try Pi, the unopinionated coding harness, instead of OpenCode.&lt;/p&gt;

&lt;p&gt;The idea was simple: keep my existing model setup, put Pi in front of it, and see how a less opinionated coding harness felt.&lt;/p&gt;

&lt;p&gt;I already had OpenCodex (OCX) running as my local model proxy, so I expected this to be mostly configuration.&lt;/p&gt;

&lt;p&gt;Instead, Muse Spark 1.2 Contributor Free started returning HTTP 500 errors.&lt;/p&gt;

&lt;p&gt;What followed was a surprisingly deep rabbit hole involving OpenAI-compatible APIs, mitmproxy, OCX's adapter routing, and eventually a model-specific protocol mismatch.&lt;/p&gt;

&lt;p&gt;And the final fix was only one configuration entry.&lt;/p&gt;

&lt;p&gt;The setup&lt;/p&gt;

&lt;p&gt;My intended architecture was:&lt;/p&gt;

&lt;p&gt;Pi&lt;br&gt;
 ↓&lt;br&gt;
OpenCodex (OCX)&lt;br&gt;
 ↓&lt;br&gt;
Model providers&lt;/p&gt;

&lt;p&gt;OCX exposes an OpenAI-compatible local API, so Pi could use it as its model backend.&lt;/p&gt;

&lt;p&gt;Muse Spark 1.2 Contributor Free was already available through the OpenCode provider:&lt;/p&gt;

&lt;p&gt;opencode-free/muse-spark-1.2-contributor-free&lt;/p&gt;

&lt;p&gt;It was visible in live model discovery and the provider itself was reachable.&lt;/p&gt;

&lt;p&gt;But requests through OCX returned:&lt;/p&gt;

&lt;p&gt;500 Internal Server Error&lt;br&gt;
First suspicion: authentication&lt;/p&gt;

&lt;p&gt;The first thing I checked was authentication.&lt;/p&gt;

&lt;p&gt;OCX's provider logs showed requests like:&lt;/p&gt;

&lt;p&gt;[ocx:openai-chat:request]&lt;br&gt;
{&lt;br&gt;
  "host": "opencode.ai",&lt;br&gt;
  "model": "muse-spark-1.2-contributor-free",&lt;br&gt;
  "stream": false,&lt;br&gt;
  "messageCount": 1,&lt;br&gt;
  "toolCount": 0,&lt;br&gt;
  "hasCredential": false&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The hasCredential: false looked suspicious.&lt;/p&gt;

&lt;p&gt;I tested the provider directly and OCX reported:&lt;/p&gt;

&lt;p&gt;Connected — 64 models available.&lt;/p&gt;

&lt;p&gt;So the provider itself was reachable.&lt;/p&gt;

&lt;p&gt;I also tested with and without an authorization header.&lt;/p&gt;

&lt;p&gt;The result was still a 500 for the free Muse model.&lt;/p&gt;

&lt;p&gt;Authentication wasn't the real problem.&lt;/p&gt;

&lt;p&gt;OpenCode was the clue&lt;/p&gt;

&lt;p&gt;There was one useful fact:&lt;/p&gt;

&lt;p&gt;OpenCode could use the exact same model successfully.&lt;/p&gt;

&lt;p&gt;That gave me something much better than guessing.&lt;/p&gt;

&lt;p&gt;Instead of asking what should happen, I could see what a working client was actually doing.&lt;/p&gt;

&lt;p&gt;So I put OpenCode's traffic through mitmproxy.&lt;/p&gt;

&lt;p&gt;That's where I found the important difference.&lt;/p&gt;

&lt;p&gt;OpenCode was sending Muse Spark through:&lt;/p&gt;

&lt;p&gt;POST /zen/v1/responses&lt;/p&gt;

&lt;p&gt;not Chat Completions.&lt;/p&gt;

&lt;p&gt;The request looked roughly like:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "model": "muse-spark-1.2-contributor-free",&lt;br&gt;
  "input": [...],&lt;br&gt;
  "max_output_tokens": 32000,&lt;br&gt;
  "reasoning": {&lt;br&gt;
    "effort": "xhigh",&lt;br&gt;
    "summary": "auto"&lt;br&gt;
  },&lt;br&gt;
  "stream": true&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;And the upstream response was:&lt;/p&gt;

&lt;p&gt;HTTP/1.1 200 OK&lt;br&gt;
Content-Type: text/event-stream&lt;/p&gt;

&lt;p&gt;The stream contained the Responses API events, including reasoning and output text events, and completed successfully.&lt;/p&gt;

&lt;p&gt;So the upstream model was working.&lt;/p&gt;

&lt;p&gt;Now I had a much more interesting question:&lt;/p&gt;

&lt;p&gt;Why was OCX getting a 500 when OpenCode wasn't?&lt;/p&gt;

&lt;p&gt;Looking at the adapter&lt;/p&gt;

&lt;p&gt;I started digging through the OCX source.&lt;/p&gt;

&lt;p&gt;OCX has separate adapters for different OpenAI-compatible protocols, including:&lt;/p&gt;

&lt;p&gt;openai-chat&lt;br&gt;
openai-responses&lt;/p&gt;

&lt;p&gt;My opencode-free provider was configured with:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "adapter": "openai-chat",&lt;br&gt;
  "baseUrl": "&lt;a href="https://opencode.ai/zen/v1" rel="noopener noreferrer"&gt;https://opencode.ai/zen/v1&lt;/a&gt;"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;And the logs confirmed that Muse was being routed through the openai-chat adapter.&lt;/p&gt;

&lt;p&gt;That gave me the mismatch:&lt;/p&gt;

&lt;p&gt;OpenCode&lt;br&gt;
  ↓&lt;br&gt;
Muse Spark&lt;br&gt;
  ↓&lt;br&gt;
/responses&lt;br&gt;
  ↓&lt;br&gt;
200 OK&lt;/p&gt;

&lt;p&gt;while OCX was effectively doing:&lt;/p&gt;

&lt;p&gt;OCX&lt;br&gt;
  ↓&lt;br&gt;
Muse Spark&lt;br&gt;
  ↓&lt;br&gt;
openai-chat&lt;br&gt;
  ↓&lt;br&gt;
Chat Completions&lt;br&gt;
  ↓&lt;br&gt;
500&lt;/p&gt;

&lt;p&gt;The provider was OpenAI-compatible.&lt;/p&gt;

&lt;p&gt;But that didn't mean every model necessarily wanted the same OpenAI-compatible wire.&lt;/p&gt;

&lt;p&gt;The nice part: per-model routing&lt;/p&gt;

&lt;p&gt;I didn't want to change the entire provider to openai-responses.&lt;/p&gt;

&lt;p&gt;Other models were already working with the existing configuration.&lt;/p&gt;

&lt;p&gt;While looking through OCX's configuration and adapter handling, I found support for per-model adapter selection.&lt;/p&gt;

&lt;p&gt;That meant I could keep the provider itself on openai-chat and tell OCX that Muse Spark should use the Responses adapter.&lt;/p&gt;

&lt;p&gt;I added:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "modelAdapters": {&lt;br&gt;
    "muse-spark-1.2-contributor-free": "openai-responses"&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After applying the configuration, OCX reported the model-specific adapter:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "muse-spark-1.2-contributor-free": "openai-responses"&lt;br&gt;
}&lt;br&gt;
And then it worked&lt;/p&gt;

&lt;p&gt;I sent the same request again.&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;p&gt;500 Internal Server Error&lt;/p&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;p&gt;200 OK&lt;/p&gt;

&lt;p&gt;The response was:&lt;/p&gt;

&lt;p&gt;OCX Muse works&lt;/p&gt;

&lt;p&gt;The final routing became:&lt;/p&gt;

&lt;p&gt;Pi&lt;br&gt;
 ↓&lt;br&gt;
OCX&lt;br&gt;
 ↓&lt;br&gt;
opencode-free&lt;br&gt;
 ↓&lt;br&gt;
Muse Spark&lt;br&gt;
 ↓&lt;br&gt;
openai-responses&lt;br&gt;
 ↓&lt;br&gt;
/zen/v1/responses&lt;br&gt;
 ↓&lt;br&gt;
200 OK&lt;br&gt;
The funny part&lt;/p&gt;

&lt;p&gt;The entire investigation started because I wanted to try Pi.&lt;/p&gt;

&lt;p&gt;I wasn't trying to reverse-engineer Muse Spark.&lt;/p&gt;

&lt;p&gt;I wasn't trying to investigate OpenCode's HTTP implementation.&lt;/p&gt;

&lt;p&gt;I wasn't even trying to debug OCX.&lt;/p&gt;

&lt;p&gt;I just wanted to see what happened if I switched from OpenCode to a more unopinionated coding harness while keeping my existing model infrastructure.&lt;/p&gt;

&lt;p&gt;That turned into:&lt;/p&gt;

&lt;p&gt;Pi&lt;br&gt;
 ↓&lt;br&gt;
500 error&lt;br&gt;
 ↓&lt;br&gt;
Check credentials&lt;br&gt;
 ↓&lt;br&gt;
Check provider&lt;br&gt;
 ↓&lt;br&gt;
Compare with OpenCode&lt;br&gt;
 ↓&lt;br&gt;
mitmproxy&lt;br&gt;
 ↓&lt;br&gt;
Observe /responses&lt;br&gt;
 ↓&lt;br&gt;
Inspect OCX source&lt;br&gt;
 ↓&lt;br&gt;
Find model-specific adapter routing&lt;br&gt;
 ↓&lt;br&gt;
openai-responses&lt;br&gt;
 ↓&lt;br&gt;
200 OK&lt;/p&gt;

&lt;p&gt;And honestly, this was one of those debugging sessions where the final configuration change is tiny, but getting to it is the interesting part.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;/p&gt;

&lt;p&gt;The biggest lesson for me was that "OpenAI-compatible" is not necessarily one single wire protocol.&lt;/p&gt;

&lt;p&gt;A provider can expose multiple models while different models—or different clients—may expect different API surfaces.&lt;/p&gt;

&lt;p&gt;In this case, the model worked through the Responses API, while my proxy was initially sending it through the Chat Completions adapter.&lt;/p&gt;

&lt;p&gt;The most useful debugging step wasn't staring at the 500.&lt;/p&gt;

&lt;p&gt;It was capturing the request from the client that already worked and asking:&lt;/p&gt;

&lt;p&gt;"What is this client actually sending?"&lt;/p&gt;

&lt;p&gt;That turned a vague 500 into a concrete protocol mismatch.&lt;/p&gt;

&lt;p&gt;And all of this because I wanted to try another coding harness. 😄&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
