ErrLookupBackground articles › "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries

"You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries

"Not allowed", 403 Forbidden, and "you do not have permission" errors mean the request was authenticated but the caller's role, scope, or permissions did not cover the action. This guide explains why servers reject authorized callers, the common causes — missing role grants, scoped keys acting on more-privileged objects, admin-only endpoints hit with user tokens, and anti-escalation guards — and how to fix them.

Distilled from 111 documented records across 31 repositories.

Background

This family sits at the authorization layer: the server has already identified the caller (a valid API key, session, OAuth token, or DDP/WebSocket session) and is now refusing the action itself. Unlike a 401, retrying with the same credentials will not help — the fix is a different credential, a changed role, or a narrower request. Libraries surface it in many shapes: HTTP 403 (tailscale's localapi, litellm's guards, InvokeAI board moves, Nextcloud trashbin), HTTP 400 with an explanatory message (litellm admin-view gates, Immich key rotation), Meteor.Error codes like 'error-not-allowed' or 'error-board-notAdmin' (Rocket.Chat, Wekan), JSON-RPC AuthorizationException -32001 (Leantime), or backend error codes like NotPermitted/PrivilegesRequired that frontend interceptors translate into redirects (pentagi).

Why the check exists varies, but the records cluster around a few rationales. Privilege separation: litellm reserves fields like estimated_output_tokens and allowed_passthrough_routes for proxy admins because letting lower roles set them would undermine limits or let an entity escalate itself. Tenant isolation: litellm's analytics guard blocks service-account keys (which have no user_id) from self-scoped analytics because a null entity id would mean 'no filter' and leak every tenant's data. Anti-escalation: Immich refuses to rotate a key whose permissions exceed the calling key's — otherwise a narrow key could learn the secret of a broader one; Appwrite rejects upserts that grant permission roles the caller does not hold, and restricts bulk transaction actions to API keys and admins because bulk operations skip per-record permission checks. Ownership: Navidrome, InvokeAI, and Nextcloud gate mutations on owning the specific object — you can see a shared playlist, calendar, or board but not modify it.

From the caller's side the error is often confusing because the object clearly exists and the credentials are valid. Several libraries deliberately blur the line between 403 and 404: Navidrome returns 403 only when the playlist is visible to you (invisible ones get 404), while litellm embeds the caller's resolved role and user_id in the error detail so you can tell 'wrong key on the header' from 'genuinely missing grant'. A recurring trap is that the permission checked is not the one you assumed: Rocket.Chat's incoming-integration check tests the post-as user's message-impersonate permission, not the caller's; Immich's rotate check applies only to API-key auth (session calls pass); Leantime's task-sort gate uses the global session role while a later check uses per-project assignment; Wekan reads the isAdmin flag server-side regardless of what the client UI showed.

Across libraries, the shape of the permission model explains most variance: global role ladders (Leantime editor+, Wekan isAdmin), per-room or per-object grants (Rocket.Chat room permissions, Navidrome playlist ownership, Nextcloud shared_access READ_WRITE vs READ), key/scope systems (claude-mem's memories:admin scope, Immich permission subsets, Appwrite documents.write scope), and object-type gates (smart/locked playlists, non-federated rooms, lifecycle integration events). The common thread: the server models some privilege above authentication, and this error is that model saying no.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 91 more across the corpus — use search.

Honest provenance: generated on 2026-09-01 from AI-assisted analysis of the linked records. See how records are made.