{"record":{"id":"9b1e3d80c8b6f28e","repo":"invoke-ai/InvokeAI","slug":"unexpected-error-while-canceling-by-batch-id-e","errorCode":null,"errorMessage":"Unexpected error while canceling by batch id: {e}","messagePattern":"Unexpected error while canceling by batch id: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"invokeai/app/api/routers/session_queue.py","lineNumber":352,"sourceCode":"@session_queue_router.put(\n    \"/{queue_id}/cancel_by_batch_ids\",\n    operation_id=\"cancel_by_batch_ids\",\n    responses={200: {\"model\": CancelByBatchIDsResult}},\n)\ndef cancel_by_batch_ids(\n    current_user: CurrentUserOrDefault,\n    queue_id: str = Path(description=\"The queue id to perform this operation on\"),\n    batch_ids: list[str] = Body(description=\"The list of batch_ids to cancel all queue items for\", embed=True),\n) -> CancelByBatchIDsResult:\n    \"\"\"Immediately cancels all queue items from the given batch ids. Non-admin users can only cancel their own items.\"\"\"\n    try:\n        # Admin users can cancel all items, non-admin users can only cancel their own\n        user_id = None if current_user.is_admin else current_user.user_id\n        return ApiDependencies.invoker.services.session_queue.cancel_by_batch_ids(\n            queue_id=queue_id, batch_ids=batch_ids, user_id=user_id\n        )\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=f\"Unexpected error while canceling by batch id: {e}\")\n\n\n@session_queue_router.put(\n    \"/{queue_id}/cancel_by_destination\",\n    operation_id=\"cancel_by_destination\",\n    responses={200: {\"model\": CancelByDestinationResult}},\n)\ndef cancel_by_destination(\n    current_user: CurrentUserOrDefault,\n    queue_id: str = Path(description=\"The queue id to perform this operation on\"),\n    destination: str = Query(description=\"The destination to cancel all queue items for\"),\n) -> CancelByDestinationResult:\n    \"\"\"Immediately cancels all queue items with the given destination. Non-admin users can only cancel their own items.\"\"\"\n    try:\n        # Admin users can cancel all items, non-admin users can only cancel their own\n        user_id = None if current_user.is_admin else current_user.user_id\n        return ApiDependencies.invoker.services.session_queue.cancel_by_destination(\n            queue_id=queue_id, destination=destination, user_id=user_id","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/session_queue.py#L334-L370","documentation":"This is a catch-all 500 handler in the cancel_by_batch_ids FastAPI route. Any unhandled exception raised by the session_queue service while canceling queue items by batch id (DB errors, service not ready, malformed input reaching the service layer) is wrapped into this HTTP 500. It hides the underlying cause in the detail string, so the original exception text is appended after the colon.","triggerScenarios":"PUT /api/v1/queue/{queue_id}/cancel_by_batch with batch_ids, when the session queue service throws: DB connection failure, invalid queue_id, SQLite/Postgres lock, or an internal service bug while executing cancel_by_batch_ids.","commonSituations":"Database is down or migrated out of sync after an InvokeAI upgrade; queue_id refers to a deleted/unknown queue; disk I/O errors on the SQLite file; concurrent queue writes causing lock contention.","solutions":["Check server logs for the full traceback printed before the HTTPException is raised — the wrapped {e} text names the real cause.","Verify the database (SQLite file or Postgres) is reachable, not locked, and at the expected schema version (run any pending migrations).","Confirm queue_id exists (GET /api/v1/queue/{queue_id}/status) before calling cancel_by_batch.","Retry after resolving DB contention; restart the InvokeAI server if the service graph failed to initialize.","Upgrade InvokeAI if the stack trace points inside session_queue service code (known bugs get fixed)."],"exampleFix":"// before (server-side catch-all obscures cause)\nexcept Exception as e:\n    raise HTTPException(500, detail=f\"Unexpected error while canceling by batch id: {e}\")\n// after (client-side: inspect and surface the wrapped cause)\ntry:\n    requests.put(f\"{base}/api/v1/queue/{queue_id}/cancel_by_batch\", json={\"batch_ids\": batch_ids})\n    resp.raise_for_status()\nexcept requests.HTTPError as e:\n    detail = e.response.json().get('detail', '')\n    if 'database is locked' in detail:\n        time.sleep(1)  # retry after DB contention\n    else:\n        raise RuntimeError(f'cancel_by_batch_ids failed: {detail}') from e","handlingStrategy":"try-catch","validationCode":"const status = await fetch(`${base}/api/v1/queue/${queueId}/status`);\nif (!status.ok) throw new Error(`queue ${queueId} unavailable`);","typeGuard":"function isQueueBatchCancelResult(v): v is { canceled_count: number } {\n  return typeof v === 'object' && v !== null && 'canceled_count' in v;\n}","tryCatchPattern":"try {\n  const r = await fetch(url, { method: 'PUT', body: JSON.stringify({ batch_ids }) });\n  if (!r.ok) {\n    const detail = (await r.json()).detail ?? '';\n    throw new Error(`cancel_by_batch failed: ${detail}`);\n  }\n} catch (e) {\n  logger.error('cancel_by_batch_ids 500', e);\n  // check DB/server health before retry\n}","preventionTips":["Log response detail — the wrapped {e} names the real cause","Verify queue_id exists before canceling","Check DB health (migrations, locks) on 500s","Retry only after resolving the underlying DB condition"],"tags":["http-500","fastapi","queue","database"],"backgroundTag":"unhandled-exception-wrapped-as-500","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}