Bug
POST /session/{id}/command returns HTTP 500 when the session's stored directory in the database points to a path that no longer exists (e.g. the project was moved or deleted after the session was created).
Steps to Reproduce
- Open a project at
/path/to/old-location in the web UI
- Send a command message — works fine
- Move the project directory:
mv /path/to/old-location /path/to/new-location
- Restart opencode (
opencode web), open the web UI
- The old session appears in the session list
- Type a message and send → HTTP 500 returned
noReply: true messages (e.g. /compact) succeed because they bypass the code path that validates the directory
Root Cause
The WorkspaceRoutingMiddleware extracts session?.directory from the session's database row and sets it as the routing directory. This directory is used by InstanceContextMiddleware to load the instance context, which initializes a FileSystem service rooted at that path. When the directory no longer exists, FileSystem.realPath() fails with ENOENT.
Because SystemPrompt.environment() (system.ts) has signature Effect<string[]> (no error type), the Fail from a missing directory is converted to a Die defect. This Die bypasses the handler's Effect.mapError(() => new HttpApiError.BadRequest({})) — which only catches Fail causes — and hits the default 500 error handler.
Error chain:
SessionHttpApi.command
→ SessionPrompt.command → prompt → loop → ensureRunning → runLoop
→ SystemPrompt.environment()
→ ctx.directory (from stale session row)
→ LocationServiceMap.get(ref) → FileSystem.realPath(stale directory) → ENOENT
→ Die defect → bypasses Effect.mapError(→BadRequest) → 500
Affected code
packages/opencode/src/session/system.ts — SystemPrompt.environment() has no error channel, so any location boot failure becomes a Die
packages/opencode/src/project/project.ts — fromDirectory() does not relink stale session directories when a project moves
packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts — requireSession() does not validate that the stored directory still exists on disk
Related issues
Suggested fix approach
Three fixes that together cover all three related reports:
- system.ts: Wrap the location layer call with
Effect.catchCause so ENOENT degrades to empty references instead of a Die defect
- project.ts: In
fromDirectory(), auto-relink sessions under the same project_id whose directory no longer exists on disk
- handlers/session.ts: In
requireSession(), check that the stored directory exists on disk and return 400 BadRequest if not
Bug
POST /session/{id}/commandreturns HTTP 500 when the session's storeddirectoryin the database points to a path that no longer exists (e.g. the project was moved or deleted after the session was created).Steps to Reproduce
/path/to/old-locationin the web UImv /path/to/old-location /path/to/new-locationopencode web), open the web UInoReply: truemessages (e.g./compact) succeed because they bypass the code path that validates the directoryRoot Cause
The
WorkspaceRoutingMiddlewareextractssession?.directoryfrom the session's database row and sets it as the routing directory. This directory is used byInstanceContextMiddlewareto load the instance context, which initializes aFileSystemservice rooted at that path. When the directory no longer exists,FileSystem.realPath()fails withENOENT.Because
SystemPrompt.environment()(system.ts) has signatureEffect<string[]>(no error type), theFailfrom a missing directory is converted to aDiedefect. ThisDiebypasses the handler'sEffect.mapError(() => new HttpApiError.BadRequest({}))— which only catchesFailcauses — and hits the default 500 error handler.Error chain:
Affected code
packages/opencode/src/session/system.ts—SystemPrompt.environment()has no error channel, so any location boot failure becomes a Diepackages/opencode/src/project/project.ts—fromDirectory()does not relink stale session directories when a project movespackages/opencode/src/server/routes/instance/httpapi/handlers/session.ts—requireSession()does not validate that the stored directory still exists on diskRelated issues
opencode run --session <id>hangs silently when session.directory is staleSuggested fix approach
Three fixes that together cover all three related reports:
Effect.catchCauseso ENOENT degrades to empty references instead of a Die defectfromDirectory(), auto-relink sessions under the same project_id whose directory no longer exists on diskrequireSession(), check that the stored directory exists on disk and return400 BadRequestif not