Claude Admin API Workspace Not Found — Fix 404 (2026) | AI Error Hub
Anthropic Claude Admin API Severity: Medium HTTP 404

Claude Admin API Workspace not_found_error — Wrong ID, Wrong Org, or No Access

Claude Admin API returned 404 not_found_error when you tried to access a workspace. The workspace_id might be wrong, might belong to a different org, or your admin key might not have workspace-scope access. This page covers workspace ID formats, org boundaries, and multi-workspace routing.

Error code: not_found_error HTTP: 404 Category: Admin API Last tested: Nov 16, 2026
Quick Fix (TL;DR)

Workspace IDs are prefixed wrkspc_ — not to be confused with org IDs (org_). Confirm your admin key belongs to the org that owns the workspace. Use list_workspaces to enumerate valid IDs. Never hardcode workspace IDs across environments — store in config keyed by env name and validate at boot.

The Error Messages You're Seeing

Response body variants
# Wrong ID:
HTTP/1.1 404 Not Found
{"type":"error","error":{"type":"not_found_error",
  "message":"Workspace wrkspc_01ABC not found in organization org_01XYZ."}}

# Cross-org 404 — workspace exists but different org:
{"type":"error","error":{"type":"not_found_error",
  "message":"Workspace wrkspc_01ABC not accessible with the provided admin key. 
  Verify the key belongs to the correct organization."}}

# Malformed ID (swapped org_ for wrkspc_):
{"type":"error","error":{"type":"invalid_request_error",
  "message":"Invalid workspace_id format. Expected 'wrkspc_' prefix followed 
  by 24 alphanumeric characters."}}

# Deleted workspace:
{"type":"error","error":{"type":"not_found_error",
  "message":"Workspace wrkspc_01ABC has been deleted. 
  Deleted workspaces cannot be restored via API."}}

ID Prefixes Reference (Nov 2026)

PrefixEntityExampleScope
org_Organizationorg_01ABC…Top-level container
wrkspc_Workspacewrkspc_01DEF…Under one org
usr_User (member)usr_01GHI…Global; can span orgs
apikey_API key metadataapikey_01JKL…Per workspace or org
invite_Pending inviteinvite_01MNO…Per org

Never confuse org_ and wrkspc_ — swapping them is a top cause of 404s.

What Actually Causes This Error

32%
Passed org_id where workspace_id was expectedSimilar-looking prefixes; wrong slot in URL
24%
Workspace deleted or archivedCleanup happened, code still references old ID
16%
Cross-org access attemptMulti-tenant app leaking workspace_id across orgs
12%
Typo or truncated IDCopy-paste dropped chars from ID
10%
Hardcoded workspace_id across environmentsProd ID reused in staging or vice versa
6%
Admin key scope excludes this workspaceWorkspace-scoped admin key on unauthorized workspace

Fixes That Work (Tested Nov 2026)

1Enumerate Workspaces Before Referencing

Python · discovery-first
import httpx import os ADMIN_KEY = os.environ["ANTHROPIC_ADMIN_KEY"] ORG_ID = os.environ["ANTHROPIC_ORG_ID"] BASE = "https://api.anthropic.com" HEADERS = {"x-api-key": ADMIN_KEY, "anthropic-version": "2023-06-01"} def list_workspaces() -> list: with httpx.Client() as c: r = c.get(f"{BASE}/v1/organizations/{ORG_ID}/workspaces", headers=HEADERS, timeout=30) r.raise_for_status() return r.json()["data"] def find_workspace_by_name(name: str) -> dict: for ws in list_workspaces(): if ws["name"] == name: return ws raise LookupError(f"No workspace named '{name}'") def validate_workspace_id(ws_id: str) -> bool: if not ws_id.startswith("wrkspc_"): return False with httpx.Client() as c: r = c.get(f"{BASE}/v1/organizations/{ORG_ID}/workspaces/{ws_id}", headers=HEADERS) return r.status_code == 200 # Boot-time safe lookup: prod_ws = find_workspace_by_name("production") stg_ws = find_workspace_by_name("staging") print(f"prod: {prod_ws['id']}") print(f"stg: {stg_ws['id']}")

2Config-Driven Multi-Workspace Routing

Python · env-aware config
import os import yaml from functools import lru_cache # workspaces.yaml (checked into repo, IDs from secret manager): # envs: # production: ${PROD_WORKSPACE_ID} # staging: ${STG_WORKSPACE_ID} # customer_acme: ${ACME_WORKSPACE_ID} @lru_cache(maxsize=1) def load_workspace_config() -> dict: with open("/etc/app/workspaces.yaml") as f: raw = f.read() # Expand env vars import os, re expanded = re.sub(r"\$\{(\w+)\}", lambda m: os.environ[m.group(1)], raw) return yaml.safe_load(expanded)["envs"] def get_workspace_id(env: str) -> str: config = load_workspace_config() ws_id = config.get(env) if not ws_id: raise KeyError(f"No workspace configured for env '{env}'") if not ws_id.startswith("wrkspc_"): raise ValueError(f"Malformed workspace_id: {ws_id}") return ws_id # For multi-tenant SaaS: map customer_id → workspace_id in DB def get_customer_workspace(customer_id: str) -> str: """Look up in database rather than hardcode.""" row = db.query("SELECT workspace_id FROM customers WHERE id=%s", customer_id) if not row or not row.workspace_id.startswith("wrkspc_"): raise LookupError(f"No valid workspace for customer {customer_id}") return row.workspace_id

3Handle Deleted Workspaces Gracefully

Python · resilient wrapper
import httpx class WorkspaceDeleted(Exception): pass class WorkspaceAccessDenied(Exception): pass def workspace_call(method: str, path: str, ws_id: str, **kwargs): """Call any admin endpoint scoped to a workspace with useful errors.""" url = f"{BASE}/v1/organizations/{ORG_ID}/workspaces/{ws_id}{path}" with httpx.Client() as c: r = c.request(method, url, headers=HEADERS, **kwargs) if r.status_code == 404: body = r.json().get("error", {}) msg = body.get("message", "").lower() if "deleted" in msg: raise WorkspaceDeleted(f"Workspace {ws_id} was deleted") if "not accessible" in msg: raise WorkspaceAccessDenied( f"Admin key cannot access {ws_id} — check org scope" ) raise LookupError(f"Workspace {ws_id} not found") r.raise_for_status() return r.json() # Usage: try: members = workspace_call("GET", "/members", "wrkspc_01ABC") except WorkspaceDeleted: # Update your DB — this workspace is gone forever db.execute("UPDATE customers SET workspace_id=NULL WHERE workspace_id=%s", "wrkspc_01ABC") raise except WorkspaceAccessDenied: # Alert the ops team — likely misconfigured admin key alerts.send("Admin key lost access to workspace") raise

Preventing This Error Going Forward

  • Never hardcode workspace_ids. Store in secret manager or config keyed by env name.
  • Validate workspace_id prefix at every ingest point. Regex ^wrkspc_[a-zA-Z0-9]{24}$.
  • Cache workspace lookups but with TTL. Deleted workspaces don't fix themselves; expire cache.
  • Track workspace_id → customer_id mapping in DB. Multi-tenant SaaS: never derive from user input.
  • Log every 404 with request context. Reveals leaks and misrouting.
  • Test the 'deleted workspace' scenario. Mock the 404 explicitly in integration tests.
  • Distinguish 'not found' from 'access denied' in retries. Different recovery paths.
SK
Tested by Sana K.
Researcher · AI Error Hub
Last verified: Nov 15, 2026 · SDK: anthropic-python 0.40+

Frequently Asked Questions

An organization is the top-level entity that owns billing, members, and admin keys. A workspace is a sub-scope within an org — you can have many workspaces per org, each with its own API keys and quotas. Confusing them is a common cause of 404s because they look similar.

No. Once deleted, a workspace_id is permanently retired. New workspaces get fresh IDs. This is intentional to prevent zombie references from resurrecting old data.

There's no direct move API. You must: (a) upload files/keys/members to the new workspace, (b) verify functionality, (c) delete from old. For customer migrations, script this and run during a maintenance window.

No. workspace_ids are globally unique but only accessible with an admin key from the owning org. Two orgs can't accidentally see each other's workspace metadata even if they somehow learn the ID.

Check client.beta.organizations.list() with any admin key — it returns all orgs your admin key can access. On the Console, org_id is visible under Settings → Organization Info.