{"record":{"id":"4054e1c9b44db286","repo":"paperclipai/paperclip","slug":"creating-companies-requires-board-instance-admin-a","errorCode":null,"errorMessage":"Creating companies requires board/instance-admin authentication. Agent API keys are scoped to one company; use `paperclipai company list --json` or `paperclipai company current --json` to select the scoped company, or rerun create with a board token/login.","messagePattern":"Creating companies requires board/instance-admin authentication\\. Agent API keys are scoped to one company; use `paperclipai company list --json` or `paperclipai company current --json` to select the scoped company, or rerun create with a board token/login\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/company.ts","lineNumber":2024,"sourceCode":"  } catch (error) {\n    if (!isBoardAccessRequiredError(error)) {\n      throw error;\n    }\n  }\n\n  const companyId = await resolveCurrentCompanyId(ctx);\n  const scopedCompany = await ctx.api.get<Company>(apiPath`/api/companies/${companyId}`);\n  return scopedCompany ? [scopedCompany] : [];\n}\n\nasync function createCompanyForContext(ctx: {\n  api: { post<T>(path: string, body?: unknown): Promise<T | null> };\n}, payload: unknown): Promise<unknown> {\n  try {\n    return await ctx.api.post(\"/api/companies\", payload);\n  } catch (error) {\n    if (isBoardAccessRequiredError(error) || isInstanceAdminRequiredError(error)) {\n      throw new Error(\n        \"Creating companies requires board/instance-admin authentication. Agent API keys are scoped to one company; use `paperclipai company list --json` or `paperclipai company current --json` to select the scoped company, or rerun create with a board token/login.\",\n      );\n    }\n    throw error;\n  }\n}\n\nasync function resolveCurrentCompanyId(ctx: { companyId?: string; api: { get<T>(path: string): Promise<T | null> } }): Promise<string> {\n  const fromContext = ctx.companyId?.trim();\n  if (fromContext) return fromContext;\n\n  let agent: AgentMeResponse | null = null;\n  try {\n    agent = await ctx.api.get<AgentMeResponse>(\"/api/agents/me\");\n  } catch (error) {\n    if (error instanceof ApiRequestError && (error.status === 401 || error.status === 403)) {\n      throw new Error(\n        \"Current company is not available. Pass --company-id, set PAPERCLIP_COMPANY_ID, set a context profile companyId, or authenticate with an agent API key.\",","sourceCodeStart":2006,"sourceCodeEnd":2042,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/client/company.ts#L2006-L2042","documentation":"Thrown by createCompanyForContext() when the POST /api/companies fails with a 403 whose message indicates 'board access required' or 'instance admin'. Creating companies is a board/instance-admin privilege; agent API keys are scoped to a single existing company and cannot create new ones. The helper detects both 403 variants and re-throws a user-facing explanation.","triggerScenarios":"Running `paperclipai company create` with an agent API key; a token that is company-scoped rather than board-scoped; a context profile configured with persona 'agent'.","commonSituations":"Agent automation attempting to bootstrap a new company; CI using an agent key for provisioning; the default context was set up via agent auth instead of board auth.","solutions":["Authenticate as board: run `paperclipai connect` and choose the board persona, or set a board API key via PAPERCLIP_API_KEY.","Provision the company out-of-band (admin UI / API directly) and then have agents reference it.","Confirm the token's scope with `paperclipai context current`."],"exampleFix":"# before\nexport PAPERCLIP_API_KEY=$AGENT_KEY\npaperclipai company create --name newco\n# after\nexport PAPERCLIP_API_KEY=$BOARD_KEY\npaperclipai company create --name newco","handlingStrategy":"try-catch","validationCode":"// Guard company create behind a board-token check before calling the API.\nfunction requireBoardPersona(profile: { persona?: string }): void {\n  if (profile.persona !== \"board\") {\n    throw new Error(\"Company create requires a board/instance-admin token; run 'paperclipai connect' as board.\");\n  }\n}","typeGuard":"import { ApiRequestError } from \"../../client/http.js\";\n\nfunction isBoardOrInstanceAdmin403(err: unknown): boolean {\n  if (!(err instanceof ApiRequestError) || err.status !== 403) return false;\n  const m = err.message.toLowerCase();\n  return m.includes(\"board access required\") || m.includes(\"instance admin\");\n}","tryCatchPattern":"try {\n  return await ctx.api.post(\"/api/companies\", payload);\n} catch (err) {\n  if (isBoardOrInstanceAdmin403(err)) {\n    throw new Error(\"Switch to a board/instance-admin token to create companies.\");\n  }\n  throw err;\n}","preventionTips":["Keep a dedicated board token for provisioning workflows; separate from agent keys.","Provision companies via admin tooling, then hand agents a company-scoped key.","Assert persona === 'board' in wrappers before calling create."],"tags":["cli","company-create","authorization","forbidden","board-access","instance-admin"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}