Skip to content

Fix file-upload 404 on a brand-new chat#155

Merged
pufit merged 1 commit into
mainfrom
pufit/fix-file-upload-virtual-session
Jun 27, 2026
Merged

Fix file-upload 404 on a brand-new chat#155
pufit merged 1 commit into
mainfrom
pufit/fix-file-upload-virtual-session

Conversation

@pufit

@pufit pufit commented Jun 27, 2026

Copy link
Copy Markdown
Member

Problem

Attaching a file to a freshly-created chat fails. The browser console shows:

POST https://<host>/api/files/upload 404 (Not Found)

Root cause

It is not a missing route. POST /api/files/upload is registered and live (it's in the running app's OpenAPI; an unauthenticated POST returns 401, not 404). The 404 comes from inside the handler:

session = await deps.db.get_session(session_id)
if not session:
    raise HTTPException(status_code=404, detail="Session not found")

The lazy "new chat" flow mints a virtual session — a client-only randomUUID() (chatStore createSession) that is not persisted in the DB until the first message is sent. The code comment is explicit that this temp id "is never sent to the backend." But the file-upload path (ChatInput.addFilesapi.uploadFiles) fired immediately against that virtual id, so the backend — which had never seen it — returned 404 "Session not found". This hits every attach-to-new-chat, i.e. the most common upload moment.

Reproduced against a live server: uploading with a fake/virtual session_id404 "Session not found"; with a real persisted id → 200.

Fix

Materialize the virtual session before uploading, mirroring the existing first-message flow:

  • Extract a shared ensureRealSession(running?) store action — it POSTs /api/sessions, adopts the server-minted id, carries the unsent draft across to the new id (so the composer doesn't blank when the id swaps), and is a no-op once the chat is already real.
  • ChatInput.addFiles calls ensureRealSession() and uploads against the returned real id.
  • sendMessage now reuses the same action instead of its own inline materialization (single source of truth; send path keeps is_running: true so the sidebar spinner is instant).

Frontend-only; no backend or DB change. The session must genuinely exist (uploads are keyed by session_id on disk and in uploaded_files), so materializing — not relaxing the guard — is the correct fix.

Test plan

  • npm run build (tsc typecheck + Vite) passes
  • eslint on both changed files: clean
  • Live repro confirms fail/pass boundary (virtual id → 404, real id → 200)
  • Manual: open a new chat, attach a file before sending any message → upload succeeds (200), session appears in the sidebar, message sends with the attachment

Generated by Nerve

The "+" button mints a client-only "virtual" session that isn't
persisted in the DB until the first message is sent. Attaching a file
to such a chat uploaded against that temp id, so POST /api/files/upload
hit the handler's `if not session: 404 "Session not found"` guard — a
404 that looked like a missing route but was application-level.

Extract a shared `ensureRealSession()` store action that materializes
the virtual session (POST /api/sessions, adopt the server id, carry the
draft across) and call it before uploading, so the upload targets a real
session row. sendMessage now reuses the same action instead of its own
inline materialization.
@pufit pufit merged commit 6828c78 into main Jun 27, 2026
2 checks passed
@pufit pufit deleted the pufit/fix-file-upload-virtual-session branch June 27, 2026 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant