Skip to content

[WSL2] Installer (07-devtools): reinstall corrupts opencode.json — sed strips trailing comma → invalid JSON, opencode-web crash-loops #309

@yasinBursali

Description

@yasinBursali

Environment

Description

On a reinstall (when ~/.config/opencode/opencode.json already exists from a prior install), the installer's "update API key and URL in existing config" code path uses sed to rewrite the baseURL line. The sed pattern is greedy through end-of-line and drops the trailing comma, leaving:

"options": {
    "baseURL": "http://127.0.0.1:11434/v1"   <-- missing comma
    "apiKey": "no-key"
},

That is invalid JSON. The downstream opencode-web.service (user systemd unit) parses the file with cp opencode.json config.json, fails with CommaExpected at line 11, column 9, and goes into a permanent crash-loop. On my machine the systemd restart counter had reached 1265 by the time I noticed, because the broken state survives across reboots.

The from-scratch heredoc generator on lines 127–152 is fine — it only triggers the bug on the update path on lines 156–157.

Steps to Reproduce

  1. Run ./install.sh --tier 1 on a clean machine — install succeeds, ~/.config/opencode/opencode.json is generated correctly with valid JSON.
  2. Run the installer a second time (any tier, any flags) — the existing-file branch in 07-devtools.sh runs the two sed commands.
  3. cat ~/.config/opencode/opencode.json — observe the missing comma after "baseURL".
  4. systemctl --user status opencode-web — observe Active: activating (auto-restart) (Result: exit-code) with high restart counter.
  5. journalctl --user -u opencode-web -n 50 — confirms CommaExpected at line 11, column 9.

Expected Behavior

A reinstall should leave opencode.json as valid JSON. The OpenCode Web service should start successfully on 127.0.0.1:3003.

Actual Behavior

opencode.json becomes invalid JSON after the first reinstall. opencode-web.service crash-loops indefinitely. Port 3003 never comes up. The installer's "Linking OpenCode Web" phase blocks for ~2 minutes waiting for the service before timing out and continuing.

Relevant Logs / Output

dream-server/installers/phases/07-devtools.sh:155-157:

# Reinstall: update API key and URL in existing config (key may have changed)
_sed_i "s|\"apiKey\":.*|\"apiKey\": \"${_opencode_key}\"|" "$OPENCODE_CONFIG_DIR/opencode.json"
_sed_i "s|\"baseURL\":.*|\"baseURL\": \"${_opencode_url}\"|" "$OPENCODE_CONFIG_DIR/opencode.json"

The .* in "baseURL":.* matches through the trailing , on the original line, and the replacement string does not put it back.

journalctl excerpt:

opencode[61671]: --- Errors ---
opencode[61671]: CommaExpected at line 11, column 9
opencode[61671]:    Line 11:         "apiKey": "no-key"
opencode[61671]:                   ^
opencode[61671]: --- End ---
systemd[233]: opencode-web.service: Failed with result 'exit-code'.
systemd[233]: opencode-web.service: Scheduled restart job, restart counter is at 1265.

Root Cause Hypothesis

The two sed patterns at 07-devtools.sh:156-157 are not JSON-aware. They match to end-of-line via .*, which on the baseURL line consumes the trailing , separator. The apiKey line is the last key inside options so it has no trailing comma — the apiKey sed is harmless. The baseURL sed is the corrupting one.

Two reasonable fixes (in increasing order of robustness):

  1. Cheap fix — preserve the trailing comma explicitly in the replacement:

    _sed_i "s|\"baseURL\": *\"[^\"]*\"|\"baseURL\": \"${_opencode_url}\"|" "$OPENCODE_CONFIG_DIR/opencode.json"
    _sed_i "s|\"apiKey\": *\"[^\"]*\"|\"apiKey\": \"${_opencode_key}\"|"  "$OPENCODE_CONFIG_DIR/opencode.json"

    Match only the quoted value, leave the rest of the line (including the comma) untouched.

  2. Robust fix — use jq if available, fall back to the regenerate-from-template path:

    if command -v jq >/dev/null 2>&1; then
      jq --arg url "$_opencode_url" --arg key "$_opencode_key" \
        '.provider["llama-server"].options.baseURL = $url
         | .provider["llama-server"].options.apiKey = $key' \
        "$OPENCODE_CONFIG_DIR/opencode.json" > "$OPENCODE_CONFIG_DIR/opencode.json.tmp" \
        && mv "$OPENCODE_CONFIG_DIR/opencode.json.tmp" "$OPENCODE_CONFIG_DIR/opencode.json"
    else
      # Fall back to the heredoc — overwrite is safer than a broken sed
      ...
    fi

Either fix should also re-sync config.json from opencode.json (the existing cp on line 161 already does this).

Severity / Impact

Medium. Doesn't break the main DreamServer stack — Open WebUI / llama-server / dashboard all install fine. But:

  • OpenCode Web (port 3003) is silently broken on every reinstall.
  • The installer's "Linking OpenCode Web" phase wastes ~2 minutes waiting for a service that will never come up.
  • A naive user re-running ./install.sh to update will degrade their working OpenCode Web setup. The bug is silent — the installer prints ✓ OpenCode config updated (API key and URL refreshed) even though it just corrupted the file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginstallerInstaller issueswsl2WSL2-specific issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions