invoke-ai/InvokeAI · critical · HTTPException
Failed to add image to board
Error message
Failed to add image to board
What it means
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.
Source
Thrown at invokeai/app/api/routers/board_images.py:172
_assert_image_direct_owner(image_name, current_user)
assert_image_move_maintenance_inactive()
try:
added_images: set[str] = set()
affected_boards: set[str] = set()
old_board_id = ApiDependencies.invoker.services.board_image_records.get_board_for_image(image_name) or "none"
ApiDependencies.invoker.services.board_images.add_image_to_board(board_id=board_id, image_name=image_name)
added_images.add(image_name)
affected_boards.add(board_id)
affected_boards.add(old_board_id)
return AddImagesToBoardResult(
added_images=list(added_images),
# Single-image route: a failure here is a 500, never a partial success.
failed_images=[],
affected_boards=list(affected_boards),
)
except Exception:
raise HTTPException(status_code=500, detail="Failed to add image to board")
@board_images_router.delete(
"/",
operation_id="remove_image_from_board",
responses={
201: {"description": "The image was removed from the board successfully"},
},
status_code=201,
response_model=RemoveImagesFromBoardResult,
)
def remove_image_from_board(
current_user: CurrentUserOrDefault,
image_name: str = Body(description="The name of the image to remove", embed=True),
) -> RemoveImagesFromBoardResult:
"""Removes an image from its board, if it had one"""
try:
old_board_id = ApiDependencies.invoker.services.images.get_dto(image_name).board_id or "none"View on GitHub (pinned to 0b6a024f2f)
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
Example fix
// before
await api.addImageToBoard({ board_id, image_name }); // opaque 500
// after
try {
await api.addImageToBoard({ board_id, image_name });
} catch (e) {
if (e.status === 500) { await retryWithBackoff(() => api.addImageToBoard({ board_id, image_name })); }
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
await assertBoardWriteAccess(boardId); // pre-check board exists and is writable await assertImageDirectOwner(imageName); // pre-check ownership before the add
Try / catch
try {
await api.addImageToBoard({ board_id: boardId, image_name });
} catch (e) {
if (e.response?.status === 500 && e.response?.data?.detail === 'Failed to add image to board') {
await retryWithBackoff(() => api.addImageToBoard({ board_id: boardId, image_name }), { attempts: 3 });
} else throw e;
} Prevention
- 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
When it happens
Trigger: Any unexpected exception during the add operation — e.g. board record service failure, database/locked storage error, serialization issue — after access checks passed.
Common situations: Locked or corrupted board database; storage backend (disk/network) errors; bugs in the board records service triggered by edge-case board states.
Related errors
- str(e)
- Failed to delete video
- call_saved_workflow could not access board '{board_id}' for
- Board not found
- Not authorized to access this board
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/98c384da921f5278.
Report an issue: GitHub.