Skip to content

[Bug]: confirm-proposal times out client-side (~35-47s) but backend finishes the spine build anyway #607

Description

@machug

Do you need to file an issue?

  • I have searched the existing issues and this bug is not already filed.
  • I believe this is a legitimate bug, not just a question or feature request.

Describe the bug

POST /api/v1/book/books/confirm-proposal ("Confirm proposal & build spine" button) reliably fails client-side with a proxy error after ~35-47s, even though the backend keeps working and successfully finishes the spine generation shortly after.

Frontend/Next.js log:

Failed to proxy http://localhost:8001/api/v1/book/books/confirm-proposal Error: socket hang up
    at ignore-listed frames {
  code: 'ECONNRESET'
}

Backend log: no error, no traceback, no confirm_proposal failed line at all (see book.pyconfirm_proposal route logs logger.error(f"confirm_proposal failed: {exc}", exc_info=True) on exception, and this never appears). The backend is still mid-request when the connection drops.

I confirmed this by checking GET /api/v1/book/books on the backend directly after the failures: both affected books ended up in spine_ready / compiling state, with created_at timestamps matching the exact moment of the failed proxy calls. So the backend genuinely finishes the (multi-LLM-call) spine generation — the client/proxy just gives up first and the UI has no way to know it eventually succeeded.

Steps to reproduce

  1. Create a book from a knowledge base, get a generated proposal.
  2. Click "Confirm proposal & build spine".
  3. Wait — after ~35-47s the request errors out client-side (spinner/error, or UI appears stuck).
  4. Wait another ~30-60s and refresh My Books — the book has actually reached spine_ready anyway.

Expected Behavior

The UI shouldn't time out / error on a request that the backend is still successfully processing. Two options that seem reasonable given the existing code:

  1. confirmProposal (web/lib/book-api.ts) is a plain blocking POST that the Next.js middleware (web/proxy.ts) rewrites straight through to the backend with no timeout override — but something in the path (browser/OS network stack, most likely an idle-connection timeout with no bytes flowing for 35-47s) resets the connection before the multi-LLM spine-build finishes.
  2. There's already a WebSocket path for this exact operation — book.py's /ws handler accepts a {"type": "confirm_proposal", "book_id": ..., "proposal": {...}} message and streams progress back (confirm_proposal_result). The "Confirm proposal & build spine" button in web/app/(workspace)/book/page.tsx (handleConfirmProposal, ~line 287) calls bookApi.confirmProposal() (the blocking REST path) instead of using the already-open book WebSocket. Routing this through the WS path (which the frontend already opens for other book events) would sidestep the long-blocking-request-over-HTTP problem entirely and give real progress feedback instead of a dead spinner.

Related Module

Book Creation

Configuration Used

LLM: openrouter / anthropic/claude-sonnet-4-5
EMBEDDING: openai / text-embedding-3-large
Deployment: Docker (ghcr.io/hkuds/deeptutor:latest)

Logs and screenshots

Frontend container log excerpt:

INFO:     172.22.0.1:0 - "WebSocket /api/v1/book/ws" [accepted]
Failed to proxy http://localhost:8001/api/v1/book/books/confirm-proposal Error: socket hang up
    at ignore-listed frames {
  code: 'ECONNRESET'
}
Error: socket hang up
    at ignore-listed frames {
  code: 'ECONNRESET'
}

No corresponding backend-side error/traceback for the same request in the same log window.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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