Comfy-Org/ComfyUI · error · PermissionError

FORBIDDEN

FORBIDDEN

Error message

not owner

What it means

PermissionError raised by the ownership-verified reference fetch when the reference row has a non-empty owner_id that does not match the caller-supplied owner_id. Empty owner_id on the row is treated as unowned and allowed, so the guard only rejects genuine mismatches between two different owners.

Source

Thrown at app/assets/database/queries/asset_reference.py:99

    return session.get(AssetReference, reference_id)


def get_reference_with_owner_check(
    session: Session,
    reference_id: str,
    owner_id: str,
) -> AssetReference:
    """Fetch a reference and verify ownership.

    Raises:
        ValueError: if reference not found or soft-deleted
        PermissionError: if owner_id doesn't match
    """
    ref = get_reference_by_id(session, reference_id=reference_id)
    if not ref or ref.deleted_at is not None:
        raise ValueError(f"AssetReference {reference_id} not found")
    if ref.owner_id and ref.owner_id != owner_id:
        raise PermissionError("not owner")
    return ref


def get_reference_by_file_path(
    session: Session,
    file_path: str,
) -> AssetReference | None:
    """Get a reference by its file path."""
    return (
        session.execute(
            select(AssetReference).where(AssetReference.file_path == file_path).limit(1)
        )
        .scalars()
        .first()
    )


def count_active_siblings(

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Pass the owner_id that was recorded when the reference was created (the creating user's ID).
  2. If the reference is intentionally shared, clear/empty its owner_id in the database so the ownership check is skipped.
  3. If you administer the system, look up ref.owner_id directly and confirm which account owns the asset.
  4. Catch PermissionError at the API layer and map it to 403 rather than letting it surface as a 500.

Example fix

// before
ref = get_reference_and_verify_owner(session, reference_id=rid, owner_id=current_uid)

// after
try:
    ref = get_reference_and_verify_owner(session, reference_id=rid, owner_id=current_uid)
except PermissionError:
    raise HTTPException(status_code=403, detail="not owner")
Defensive patterns

Strategy: try-catch

Validate before calling

ref = get_reference_by_id(session, reference_id=rid)
if ref is not None and ref.owner_id and ref.owner_id != caller_owner_id:
    # reject before calling the verified fetch
    raise HTTPException(status_code=403, detail="not owner")

Try / catch

try:
    ref = get_reference_and_verify_owner(session, reference_id=rid, owner_id=uid)
except PermissionError:
    raise HTTPException(status_code=403, detail="not owner")
except ValueError:
    raise HTTPException(status_code=404, detail="reference not found")

Prevention

When it happens

Trigger: Passing an owner_id different from the reference's ref.owner_id when ref.owner_id is set (non-empty string). Happens on any owner-scoped read/update/delete of another user's reference.

Common situations: Multi-user deployments where references are created by different accounts; a client sending an empty, default, or stale owner/user identifier; tests that create references without an owner and later fetch them with an owner_id set (this passes only because owner_id on the row is empty); mixing up authenticated user IDs between services.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/cbdccddb7d2a67d8. Report an issue: GitHub.