{"record":{"id":"98c384da921f5278","repo":"invoke-ai/InvokeAI","slug":"failed-to-add-image-to-board","errorCode":null,"errorMessage":"Failed to add image to board","messagePattern":"Failed to add image to board","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"critical","filePath":"invokeai/app/api/routers/board_images.py","lineNumber":172,"sourceCode":"    _assert_image_direct_owner(image_name, current_user)\n    assert_image_move_maintenance_inactive()\n    try:\n        added_images: set[str] = set()\n        affected_boards: set[str] = set()\n        old_board_id = ApiDependencies.invoker.services.board_image_records.get_board_for_image(image_name) or \"none\"\n        ApiDependencies.invoker.services.board_images.add_image_to_board(board_id=board_id, image_name=image_name)\n        added_images.add(image_name)\n        affected_boards.add(board_id)\n        affected_boards.add(old_board_id)\n\n        return AddImagesToBoardResult(\n            added_images=list(added_images),\n            # Single-image route: a failure here is a 500, never a partial success.\n            failed_images=[],\n            affected_boards=list(affected_boards),\n        )\n    except Exception:\n        raise HTTPException(status_code=500, detail=\"Failed to add image to board\")\n\n\n@board_images_router.delete(\n    \"/\",\n    operation_id=\"remove_image_from_board\",\n    responses={\n        201: {\"description\": \"The image was removed from the board successfully\"},\n    },\n    status_code=201,\n    response_model=RemoveImagesFromBoardResult,\n)\ndef remove_image_from_board(\n    current_user: CurrentUserOrDefault,\n    image_name: str = Body(description=\"The name of the image to remove\", embed=True),\n) -> RemoveImagesFromBoardResult:\n    \"\"\"Removes an image from its board, if it had one\"\"\"\n    try:\n        old_board_id = ApiDependencies.invoker.services.images.get_dto(image_name).board_id or \"none\"","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/board_images.py#L154-L190","documentation":"add_image_to_board wraps its board-record update in a broad try/except; any exception from the underlying services is converted to HTTP 500 'Failed to add image to board'. Because this is the single-image route, a failure is a hard 500 rather than a partial success recorded in failed_images.","triggerScenarios":"Any unexpected exception during the add operation — e.g. board record service failure, database/locked storage error, serialization issue — after access checks passed.","commonSituations":"Locked or corrupted board database; storage backend (disk/network) errors; bugs in the board records service triggered by edge-case board states.","solutions":["Check server logs for the original exception stack trace behind the 500","Verify the board database/storage backend is healthy and writable (the code deliberately lets storage errors propagate from access checks, so a 500 here is likely downstream)","Retry the request; if persistent, restart the service or repair the board records store"],"exampleFix":"// before\nawait api.addImageToBoard({ board_id, image_name }); // opaque 500\n// after\ntry {\n  await api.addImageToBoard({ board_id, image_name });\n} catch (e) {\n  if (e.status === 500) { await retryWithBackoff(() => api.addImageToBoard({ board_id, image_name })); }\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"await assertBoardWriteAccess(boardId); // pre-check board exists and is writable\nawait assertImageDirectOwner(imageName); // pre-check ownership before the add","typeGuard":null,"tryCatchPattern":"try {\n  await api.addImageToBoard({ board_id: boardId, image_name });\n} catch (e) {\n  if (e.response?.status === 500 && e.response?.data?.detail === 'Failed to add image to board') {\n    await retryWithBackoff(() => api.addImageToBoard({ board_id: boardId, image_name }), { attempts: 3 });\n  } else throw e;\n}","preventionTips":["Check server logs — the 500 detail is generic, the root cause is only in the stack trace","Retry transient failures with backoff before surfacing to the user","Monitor board-record store health (locks, disk space) to prevent recurring 500s"],"tags":["http-500","server-error","board","storage"],"backgroundTag":"internal-server-error","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}