Skip to content

opencode web: child session created with ?directory= returns empty body on POST /session/{id}/message #12271

Closed as not planned

Description

@maou-shonen

Bug Description

In opencode web mode, child sessions created via POST /session?directory=/path return HTTP 200 with Content-Length: 0 (empty body) on subsequent POST /session/{id}/message calls. Child sessions created without the directory query parameter work correctly.

Environment

  • OpenCode: 1.1.51
  • Mode: opencode web
  • Platform: Linux x86_64

Steps to Reproduce

AUTH="Basic $(echo -n 'opencode:<password>' | base64)"
PARENT="<any_existing_session_id>"

# 1. Create child session WITH directory
CHILD=$(curl -s -H "Authorization: $AUTH" -H "Content-Type: application/json" \
  -X POST "http://localhost:4096/session?directory=/home/user/project" \
  -d "{\"parentID\": \"$PARENT\"}")
CHILD_ID=$(echo $CHILD | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

# 2. Send prompt — returns empty body
curl -v -H "Authorization: $AUTH" -H "Content-Type: application/json" \
  -X POST "http://localhost:4096/session/$CHILD_ID/message" \
  -d '{"agent":"sisyphus-junior","parts":[{"type":"text","text":"hello"}]}'
# → HTTP 200, Content-Length: 0, empty body

Comparison: Without directory

# Create child session WITHOUT directory
CHILD2=$(curl -s -H "Authorization: $AUTH" -H "Content-Type: application/json" \
  -X POST "http://localhost:4096/session" \
  -d "{\"parentID\": \"$PARENT\"}")
CHILD2_ID=$(echo $CHILD2 | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

# Send prompt — returns full response
curl -s -H "Authorization: $AUTH" -H "Content-Type: application/json" \
  -X POST "http://localhost:4096/session/$CHILD2_ID/message" \
  -d '{"agent":"sisyphus-junior","parts":[{"type":"text","text":"hello"}]}'
# → HTTP 200, body = 1261 bytes (valid JSON)

Controlled Experiment Results

Only variable changed is the directory parameter. Everything else (parent session, prompt body, auth) is identical:

POST /session                              → prompt ✅ body=1261 bytes
POST /session?directory=/home/user/project → prompt ❌ body=0 bytes
POST /session?directory=/home/user         → prompt ❌ body=0 bytes

Impact

The oh-my-opencode plugin passes directory when creating subagent sessions to ensure subagents operate in the correct project directory. This bug causes delegate_task (and call_omo_agent, look_at) to fail 100% of the time in opencode web mode. TUI mode is unaffected (presumably uses in-process transport rather than HTTP).

Activity

  1. github-actions commented on Feb 5, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  2. majiayu000 commented on Mar 13, 2026

    @majiayu000
    Contributor

    Hi, I've been investigating this and I believe I found the root cause.

    Root Cause

    The server middleware (server.ts) resolves the Instance context from ?directory= query param or falls back to process.cwd() for every request. When a session is created via POST /session?directory=/path, the session stores directory=/path and projectID for that directory.

    However, when POST /session/{id}/message is called without ?directory=, the middleware defaults to process.cwd(), creating an Instance context for the wrong directory. Since Instance.state() (used by SessionPrompt, Agent, etc.) is scoped per-directory, the prompt processing runs under the wrong project context. Any error thrown is silently swallowed by Hono's stream() handler, resulting in HTTP 200 with an empty body.

    Fix

    The session route handlers that process prompts (message, prompt_async, command, shell, summarize) should re-enter the correct Instance context using the session's stored directory before processing:

    const session = await Session.get(sessionID)
    return Instance.provide({
      directory: session.directory,
      async fn() {
        // ... process prompt under correct Instance context
      },
    })

    This is safe because Instance.provide() caches instances by directory — if the correct instance already exists (which it will for sessions created under the current server's CWD), the cached instance is reused with zero overhead.

    I have a working implementation with all 5 affected routes fixed. TypeScript compiles cleanly and all 1286 existing tests pass. Happy to open a PR if this approach looks right.

  3. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions