lfnovo/open-notebook · error · HTTPException
Rebuild command not found
Error message
Rebuild command not found
What it means
HTTP 404 raised by the embedding-rebuild status endpoint when surreal_commands returns no command record for the given command_id. It means the rebuild job either never existed, was garbage-collected, or its ID is malformed.
Source
Thrown at api/routers/embedding_rebuild.py:144
@router.get("/rebuild/{command_id}/status", response_model=RebuildStatusResponse)
async def get_rebuild_status(command_id: str):
"""
Get the status of a rebuild operation.
Returns:
- **status**: queued, running, completed, failed
- **progress**: processed count, total count, percentage
- **stats**: breakdown by type (sources, notes, insights, failed)
- **timestamps**: started_at, completed_at
"""
try:
# Get command status from surreal_commands
status = await get_command_status(command_id)
if not status:
raise HTTPException(status_code=404, detail="Rebuild command not found")
# Build response based on status
response = RebuildStatusResponse(
command_id=command_id,
status=status.status,
)
# Extract metadata from command result
if status.result and isinstance(status.result, dict):
result = status.result
# Build progress info
if "total_items" in result and "jobs_submitted" in result:
total = result["total_items"]
submitted = result["jobs_submitted"]
response.progress = RebuildProgress(
processed=submitted,
total=total,View on GitHub (pinned to a7de90d38a)
Solutions
- Verify the command_id matches the one returned when the rebuild was started (POST endpoint response)
- Check that SurrealDB wasn't restarted/reset — surreal_commands state lives there and is lost on reset
- If state was lost, simply start a new rebuild and use the new command_id
- Inspect surreal_commands table to confirm whether the record exists
Example fix
// before
status = await get_command_status("cmd-123")
// after: confirm the id came from the rebuild start response
resp = await client.post("/api/embedding_rebuild")
command_id = resp.json()["command_id"]
status = await client.get(f"/api/embedding_rebuild/{command_id}/status") Defensive patterns
Strategy: validation
Validate before calling
resp = await client.get(f"/api/embedding_rebuild/{command_id}/status")
if resp.status_code == 404:
# command record gone: restart the rebuild rather than polling a dead id
command_id = (await client.post("/api/embedding_rebuild")).json()["command_id"] Try / catch
try:
status = await get_rebuild_status(command_id)
except HTTPException as e:
if e.status_code == 404:
command_id = await restart_rebuild() # get fresh id and stop polling the old one
else:
raise Prevention
- Always take command_id from the start-rebuild response, never hardcode it
- Don't persist command ids across DB resets/restarts — they live in surreal_commands state
- Stop polling once status is terminal (completed/failed) to avoid hitting expired records
When it happens
Trigger: GET /api/embedding_rebuild/{command_id}/status (get_rebuild_status) where get_command_status(command_id) returns None — wrong/stale command_id from a previous rebuild, or the command store (SurrealDB) was reset/wiped between starting the rebuild and polling its status.
Common situations: Frontend polls a rebuild status after a DB reset or after the command record expired; client persists a command_id across server restarts; typo/truncation of the command ID in the URL.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Session not found
- Credential not found
- {embed_request.item_type} not found
- Episode profile '{profile_name}' not found
- Episode profile '{profile_id}' not found
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/826372d08ca86849.
Report an issue: GitHub.