odysseus-dev/odysseus · error · HTTPException
Action '{task.action}' requires admin privileges
Error message
Action '{task.action}' requires admin privileges What it means
HTTP 403 from the unauthenticated webhook trigger when the task's (task_type, action) is classified admin-only by is_admin_only_task_action() but the task owner no longer holds admin privileges (owner_has_admin_task_privileges). As a safety measure the endpoint sets the task to 'paused' and clears next_run before raising, so the privileged action cannot keep firing.
Source
Thrown at routes/task_routes.py:1064
async def webhook_trigger(task_id: str, token: str):
"""Unauthenticated endpoint — the token IS the auth."""
db = SessionLocal()
try:
task = db.query(ScheduledTask).filter(
ScheduledTask.id == task_id,
ScheduledTask.webhook_token == token,
ScheduledTask.status == "active",
).first()
if not task:
raise HTTPException(404, "Not found")
if (
is_admin_only_task_action(task.task_type, task.action)
and not owner_has_admin_task_privileges(task.owner)
):
task.status = "paused"
task.next_run = None
db.commit()
raise HTTPException(403, f"Action '{task.action}' requires admin privileges")
finally:
db.close()
started = await task_scheduler.run_task_now(task_id)
if not started:
raise HTTPException(409, "Task is already running")
return {"ok": True, "message": "Task triggered via webhook"}
@router.post("/{task_id}/webhook-regenerate")
async def regenerate_webhook(request: Request, task_id: str):
user = _owner(request)
db = SessionLocal()
try:
task = db.query(ScheduledTask).filter(ScheduledTask.id == task_id).first()
if not task:
raise HTTPException(404, "Task not found")
if user and task.owner != user:
raise HTTPException(403, "Access denied")
task.webhook_token = secrets.token_urlsafe(32)View on GitHub (pinned to f9235ebbf1)
Solutions
- Grant the task owner admin privileges, then manually resume the task (it was paused by this guard)
- Change the task's action to a non-admin equivalent so it no longer trips is_admin_only_task_action
- Delete and recreate the task under an account that holds admin privileges
Example fix
# before: task paused + 403 on webhook
# after: restore privileges and resume
UPDATE users SET is_admin=1 WHERE username='<task.owner>';
# then PUT /api/tasks/{id} with {"status":"active"} Defensive patterns
Strategy: validation
Validate before calling
const task = await getTask(taskId);
if (isAdminOnlyAction(task) && !currentUserIsAdmin(task.owner)) {
showWarning('This task requires an admin owner; it will be paused on trigger.');
} Try / catch
if (resp.status === 403) { await resumeTaskAfterPrivilegeFix(taskId); alertOwner(task.owner); } Prevention
- Audit scheduled tasks whenever user privileges change
- Expect the side effect: the task is paused before the 403 is returned
- Keep admin-only actions out of webhook-triggered tasks by design
When it happens
Trigger: POST /api/tasks/{task_id}/webhook/{token} for a task whose action is in the admin-only set (e.g. a shell/system action) after the owner's admin rights were revoked or the admin flag was never set for that user.
Common situations: An admin created a privileged scheduled task, later stepped down or the account flag changed; tasks migrated from a single-admin install into a multi-user deployment where the owner is a normal user.
Related errors
- Failed to update task
- Not found
- data.error || ('HTTP ' + (data.status || 500))
- model returned no rewritten text
- Failed to create task
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/e5e0d5c989ffcefe.
Report an issue: GitHub.