Skip to content

ctx.sendError only logs; failed WS command validation never reaches client #34

@unspecifiedcoder

Description

@unspecifiedcoder

Summary

ctx.sendError in src/server/routes/ws.ts:73-75 only writes to the server log. The 7 call sites in src/server/routes/ws/commands/message.ts and src/server/routes/ws/commands/fork.ts use it for early-return error paths (missing user, missing chat model, conversation create failure), but the client never receives any frame.

sendError: (error: string, conversationId?: string) => {
    log.warn({ error, conversationId }, 'Command error');
},

Impact

When a client sends a message or fork command, it optimistically renders a user bubble and sets isProcessing = true in its reducer. If the server short-circuits via sendError (e.g., the user picked a chatModelId that was just disabled), the client's optimistic state stays forever:

  • No spinner clears
  • No error toast
  • The "send" appears successful but never produces a response
  • This was newly exposed by commit 2cb1d88 ("Keep chat model selector in sync with conversation model"), which added three new sendError early-returns on stale chatModelId. Previously the validation didn't exist, so the bug was latent.

The client already has machinery for run-level errors: run_stopped { reason: 'error', error } (src/client/hooks/useWebSocketChat.ts:1416-1428) clears isProcessing, releases the wake lock, and fires onErrorCb.

Proposed fix

Have sendError emit a run_stopped { reason: 'error' } frame when both conversationId and runId are in scope at the call site. No new ServerMessage type; the client handler is reused.

I have a fix ready locally and will open a PR shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions