invoke-ai/InvokeAI · error · ImageFileDeleteException

Invalid staged-delete token

Error message

Invalid staged-delete token

What it means

commit_delete() validates that the token passed to it is an internal _StagedDelete instance returned by stage_delete(). Passing anything else — None, a string, or a token from a different service instance/version — raises this ImageFileDeleteException with the message "Invalid staged-delete token". It is a programming/contract error, not an I/O failure.

Source

Thrown at invokeai/app/services/image_files/image_files_disk.py:234

            for index, source in enumerate(candidates):
                with self.__cache_lock:
                    self.__cache.pop(source, None)
                if source.exists():
                    destination = staging_dir / str(index)
                    source.replace(destination)
                    staged.append((source, destination))
            return _StagedDelete(directory=staging_dir, files=staged)
        except Exception as e:
            for source, destination in reversed(staged):
                if destination.exists():
                    source.parent.mkdir(parents=True, exist_ok=True)
                    destination.replace(source)
            shutil.rmtree(staging_dir, ignore_errors=True)
            raise ImageFileDeleteException from e

    def commit_delete(self, token: object) -> None:
        if not isinstance(token, _StagedDelete):
            raise ImageFileDeleteException("Invalid staged-delete token")
        try:
            shutil.rmtree(token.directory)
        except Exception as e:
            raise ImageFileDeleteException from e

    def rollback_delete(self, token: object) -> None:
        if not isinstance(token, _StagedDelete):
            raise ImageFileDeleteException("Invalid staged-delete token")
        try:
            for source, destination in reversed(token.files):
                if destination.exists():
                    source.parent.mkdir(parents=True, exist_ok=True)
                    destination.replace(source)
            shutil.rmtree(token.directory, ignore_errors=True)
        except Exception as e:
            raise ImageFileDeleteException from e

    def get_path(self, image_name: str, thumbnail: bool = False, image_subfolder: str = "") -> Path:

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Pass the exact object returned by stage_delete() to commit_delete() in the same process
  2. Do not serialize/persist the token — treat it as an opaque in-memory handle
  3. Complete the delete lifecycle immediately after staging (stage → commit or rollback) within one session
  4. If the token was lost, locate the staging directory and restore files manually, then call rollback-free cleanup

Example fix

// before
token = services.images.stage_delete(name)
# ... later, possibly different object
services.images.commit_delete(name)  # Invalid staged-delete token
// after
token = services.images.stage_delete(name)
services.images.commit_delete(token)
Defensive patterns

Strategy: type-guard

Validate before calling

token = services.images.stage_delete(image_name)
assert token is not None

Type guard

from invokeai.app.services.image_files.image_files_disk import _StagedDelete
def is_valid_token(token: object) -> bool:
    return isinstance(token, _StagedDelete)

Try / catch

try:
    services.images.commit_delete(token)
except ImageFileDeleteException as e:
    if "Invalid staged-delete token" in str(e):
        raise TypeError("commit_delete requires the _StagedDelete from stage_delete()") from e
    raise

Prevention

When it happens

Trigger: Calling commit_delete(token) with a value not produced by stage_delete() on the same service: None, a mock, a deserialized/foreign object, or a hand-built token.

Common situations: Persisting the token to storage and passing back the wrong type; passing a token from an older InvokeAI version after upgrade; typos where a path string is passed instead of the token; test code fabricating tokens.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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