Significant-Gravitas/AutoGPT · warning · HTTPException

job belongs to a different user

Error message

job belongs to a different user

What it means

HTTP 403 from the dream-pass job status endpoint. The job was found, but its stored user_id does not equal the resolved target user (from the path's user_id or 'me'). This is an authorization guard preventing one user/admin from reading another user's job status through a mismatched path.

Source

Thrown at autogpt_platform/backend/backend/api/features/admin/memory_admin_routes.py:805

    request: Request,
    user_id: Annotated[str, Path(description="User id or 'me'")],
    job_id: Annotated[str, Path(description="Job id returned by the POST")],
    caller_id: Annotated[str, Depends(get_user_id)],
    jwt_payload: Annotated[dict, Security(get_jwt_payload)],
) -> DreamJobStatus:
    """Read the current status of a fire-and-forget dream pass job."""
    target = _resolve_user_id(user_id, caller_id)
    _audit_cross_user_access(
        request=request,
        caller_id=caller_id,
        target_id=target,
        jwt_payload=jwt_payload,
    )
    status = await read_status(kind="dream_pass", job_id=job_id)
    if status is None:
        raise HTTPException(status_code=404, detail="job not found")
    if status.user_id != target:
        raise HTTPException(status_code=403, detail="job belongs to a different user")
    return DreamJobStatus.model_validate(status.model_dump())


@router.post("/{user_id}/ratification", response_model=RatificationResult)
async def trigger_ratification_pass(
    request: Request,
    user_id: Annotated[str, Path(description="User id or 'me'")],
    caller_id: Annotated[str, Depends(get_user_id)],
    jwt_payload: Annotated[dict, Security(get_jwt_payload)],
) -> RatificationResult:
    """Trigger an on-demand ratification sweep for the user (in isolation).

    Forwards to ``Scheduler.execute_ratification_pass_now``. Runs ONLY
    the ratification supersession sweep — does NOT run dream pass or
    community rebuild. Useful for testing ratification behavior
    without the full nightly fan-out.
    """
    target = _resolve_user_id(user_id, caller_id)

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Make the path user_id identical to the one used when triggering the job (use 'me' for the caller's own jobs)
  2. Store job_id scoped per user in the client, not in a global variable
  3. In admin tooling, pass the target user's id consistently in both the trigger and status calls
  4. If cross-user inspection is required, use the admin path with the job owner's user_id, not the caller's
Defensive patterns

Strategy: validation

Validate before calling

assert trigger_user_id == poll_user_id, "path user must match the job owner"

Try / catch

except httpx.HTTPStatusError as e:
    if e.response.status_code == 403:
        # job exists but belongs to another user — do not retry with same pair
        ...

Prevention

When it happens

Trigger: GET /{user_a}/dream/{job_id}/status where job_id belongs to user_b. Happens when the path user_id is swapped after triggering (e.g. triggered as 'me' then polled with an explicit different id), when an admin fronts the call with the wrong tenant id, or when test code mixes fixtures from two users.

Common situations: Frontend stores job_id globally instead of per-user and a different logged-in user polls it; admin consoles that pass the admin's own id as user_id while replaying a customer's job_id; concurrent test sessions sharing job ids across user fixtures.

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/caf68fccdb9c191c. Report an issue: GitHub.