invoke-ai/InvokeAI · error · HTTPException

Image not found

Error message

Image not found

What it means

`_assert_image_record_exists` raises this 404 when the requested image name has no row in the image_records store. It runs on the refusal path of `assert_image_read_access` so a truly deleted image returns 404 instead of 403, telling clients the reference is permanently gone.

Source

Thrown at invokeai/app/api/routers/_access.py:81

    flipped back to Shared, an owner re-granting access), and dropping the reference over one
    destroys work the user cannot get back by restoring the permission.

    Nothing above can tell them apart: the ownership test rests on `images.user_id`, which is
    gone with the row, so a deleted image reaches that same 403 as a foreign one. So the
    distinction is made here, on the refusal path only — the happy path pays nothing for it.

    A storage error propagates rather than answering either, so an unreadable database cannot
    present as a deleted image and take the user's references down with it. `exists` is a bare
    row probe rather than `get` for the same reason from the other side: `get` deserializes, so
    a row written by a newer version — an enum value this one does not know — would fail exactly
    as absence does, and a live image would be reported gone.

    The cost is that an authenticated caller can now tell an absent image from one they may not
    read. Image names are generated UUIDs, so this buys an attacker nothing they could enumerate,
    and it is the answer admins have always received.
    """
    if not ApiDependencies.invoker.services.image_records.exists(image_name):
        raise HTTPException(status_code=404, detail="Image not found")


def assert_image_read_access(image_name: str, current_user: CurrentUserOrDefault) -> None:
    """Raise 403 if the current user may not view the image.

    Access is granted when ANY of these hold:
    - The user is an admin.
    - The user owns the image.
    - The image sits on a shared or public board.
    """
    if current_user.is_admin:
        return

    owner = ApiDependencies.invoker.services.image_records.get_user_id(image_name)
    if owner is not None and owner == current_user.user_id:
        return

    board_id = ApiDependencies.invoker.services.board_image_records.get_board_for_image(image_name)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Drop the stale image reference and pick a different image; deletion is permanent
  2. Re-generate the image (re-run the workflow/queue item) to recreate a new image name
  3. Check the database/store points at the correct storage backend (misconfigured output/DB path can make all images look missing)
  4. Confirm with an admin whether the image was removed by a pruning job (max_queue_history / disk cleanup)

Example fix

// before
const url = `/v1/images/i/${imageName}/full`;
await fetch(url); // 404 if deleted
// after
if (imageDeleted(imageName)) removeLayerFromCanvas(imageName);
else await fetch(`/v1/images/i/${imageName}/full`);
Defensive patterns

Strategy: try-catch

Validate before calling

// Check existence before dereferencing
const exists = await fetch(`/v1/images/i/${imageName}/metadata`, {headers: authHeaders}).then(r => r.ok);

Try / catch

try {
  const meta = await fetch(`/v1/images/i/${imageName}/metadata`, {headers: authHeaders}).then(r => {
    if (r.status === 404) throw new NotFoundError(imageName);
    if (!r.ok) throw new Error('fetch failed');
    return r.json();
  });
} catch (e) {
  if (e instanceof NotFoundError) removeImageReference(e.name); // 404 = permanently gone
  else throw e;
}

Prevention

When it happens

Trigger: GET of image metadata/URL/full file (e.g. /v1/images/i/{image_name}) with a UUID name that no longer exists in the database — typically after the image was deleted or pruned, while the record lookup in read-access checking fails first.

Common situations: A UI or workflow holds a reference to an image that was deleted (or its queue history pruned); stale browser tabs; shared links to images removed by cleanup jobs.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/d09711da78ff163f. Report an issue: GitHub.