invoke-ai/InvokeAI · error · HTTPException

Failed to update video

Error message

Failed to update video

What it means

Raised by update_video (PATCH videos/i/{video_name}) as HTTP 400 when the service's update(video_name, video_changes) call raises any exception. It means the record exists and the caller passed the ownership check, but applying the changes failed — typically due to invalid field values in VideoRecordChanges or a database failure. The original exception is swallowed, so the server log is needed to learn the real cause.

Solutions

  1. Inspect the server logs for the underlying exception raised by videos.update().
  2. Validate the VideoRecordChanges payload: ensure board_id references an existing board and only allowed fields are set.
  3. Re-fetch the video DTO (GET videos/i/{video_name}) and retry with a fresh, minimal changes object.
  4. Check database health (locks, disk space) if the payload is valid but the error persists.

Example fix

// before: blind full-object patch with stale fields
await api.updateVideo(name, { ...oldDto, board_id: staleBoardId });
// after
const fresh = await api.getVideoDto(name);
await api.updateVideo(name, { board_id: await ensureBoardExists(targetBoardId) });
Defensive patterns

Strategy: validation

Validate before calling

function validChanges(c) {
  return c && Object.keys(c).length > 0 &&
    (c.board_id === undefined || c.board_id === 'none' || typeof c.board_id === 'string');
}
if (!validChanges(changes)) throw new Error('Invalid VideoRecordChanges');

Type guard

function isVideoRecordChanges(v) {
  return typeof v === 'object' && v !== null &&
    !('video_name' in v) && !('created_at' in v); // changes object, not a full DTO
}

Try / catch

try {
  return await api.updateVideo(name, changes);
} catch (e) {
  if (e.response?.status === 400) {
    const fresh = await api.getVideoDto(name);
    return api.updateVideo(name, { board_id: changes.board_id }); // minimal retry
  }
  throw e;
}

Prevention

When it happens

Trigger: PATCH with a VideoRecordChanges payload containing invalid values (e.g. bad board_id, out-of-range fields), a DB write failure, or a concurrent modification conflict; also any unexpected exception inside the service update path.

Common situations: Client sending stale board_id after the board was deleted; malformed PATCH body shape; SQLite lock/disk issues; API version drift where the client sends fields the current schema rejects.

Related errors


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

Appendix: source

Thrown at invokeai/app/api/routers/videos.py:484

    return DeleteVideosResult(
        deleted_videos=list(deleted_videos),
        failed_videos=list(failed_videos),
        affected_boards=list(affected_boards),
    )


# Sync for the same reason as delete_video: the update is a blocking SQLite write.
@videos_router.patch("/i/{video_name}", operation_id="update_video", response_model=VideoDTO)
def update_video(
    current_user: CurrentUserOrDefault,
    video_name: str = PathParam(description="The name of the video to update"),
    video_changes: VideoRecordChanges = Body(description="The changes to apply to the video"),
) -> VideoDTO:
    _assert_video_owner(video_name, current_user)
    try:
        return ApiDependencies.invoker.services.videos.update(video_name, video_changes)
    except Exception:
        raise HTTPException(status_code=400, detail="Failed to update video")


@videos_router.get("/i/{video_name}", operation_id="get_video_dto", response_model=VideoDTO)
def get_video_dto(
    current_user: CurrentUserOrDefault,
    video_name: str = PathParam(description="The name of video to get"),
) -> VideoDTO:
    _assert_video_read_access(video_name, current_user)
    try:
        return ApiDependencies.invoker.services.videos.get_dto(video_name)
    except VideoRecordNotFoundException:
        # See get_image_dto: this is the 404 a workflow's video field drops its reference on,
        # so only a genuinely missing record may produce it.
        raise HTTPException(status_code=404)


@videos_router.get(
    "/i/{video_name}/metadata", operation_id="get_video_metadata", response_model=Optional[MetadataField]

View on GitHub (pinned to 0b6a024f2f)