mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-03-17 02:43:09 +00:00
fix: accept WebSocket before validation to prevent opaque 403 errors
All 5 WebSocket endpoints (expand, spec, assistant, terminal, project) were closing the connection before calling accept() when validation failed. Starlette converts pre-accept close into an HTTP 403, giving clients no meaningful error information. Server changes: - Move websocket.accept() before all validation checks in every WS handler - Send JSON error message before closing so clients get actionable errors - Fix validate_project_name usage (raises HTTPException, not returns bool) - ConnectionManager.connect() no longer calls accept() (caller's job) Client changes: - All 3 WS hooks (useWebSocket, useExpandChat, useSpecChat) skip reconnection on 4xxx close codes (application errors won't self-resolve) - Gate expand button, keyboard shortcut, and modal on hasSpec - Add hasSpec to useEffect dependency array to prevent stale closure - Update keyboard shortcuts help text for E key context Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -217,20 +217,26 @@ async def assistant_chat_websocket(websocket: WebSocket, project_name: str):
|
||||
- {"type": "error", "content": "..."} - Error message
|
||||
- {"type": "pong"} - Keep-alive pong
|
||||
"""
|
||||
if not validate_project_name(project_name):
|
||||
# Always accept WebSocket first to avoid opaque 403 errors
|
||||
await websocket.accept()
|
||||
|
||||
try:
|
||||
project_name = validate_project_name(project_name)
|
||||
except HTTPException:
|
||||
await websocket.send_json({"type": "error", "content": "Invalid project name"})
|
||||
await websocket.close(code=4000, reason="Invalid project name")
|
||||
return
|
||||
|
||||
project_dir = _get_project_path(project_name)
|
||||
if not project_dir:
|
||||
await websocket.send_json({"type": "error", "content": "Project not found in registry"})
|
||||
await websocket.close(code=4004, reason="Project not found in registry")
|
||||
return
|
||||
|
||||
if not project_dir.exists():
|
||||
await websocket.send_json({"type": "error", "content": "Project directory not found"})
|
||||
await websocket.close(code=4004, reason="Project directory not found")
|
||||
return
|
||||
|
||||
await websocket.accept()
|
||||
logger.info(f"Assistant WebSocket connected for project: {project_name}")
|
||||
|
||||
session: Optional[AssistantChatSession] = None
|
||||
|
||||
Reference in New Issue
Block a user