paperclipai/paperclip · error
Company ID is required. Pass --company-id, set…
Error message
Company ID is required. Pass --company-id, set PAPERCLIP_COMPANY_ID, or set context profile companyId via `paperclipai context set`.
What it means
HTTP 404 with body {"error":"User secret value not found"} from PATCH /api/companies/:companyId/me/user-secrets/:secretId (secrets.ts:786). svc.updateCurrentUserSecretValue(companyId, ownerUserId, secretId, ...) returned null: no secret value row matches the triple (company, current board user, secretId). The lookup is owner-scoped - a secretId belonging to another user 404s even within the same company - and it also 404s if the value was deleted or never created for this user.
Solutions
- Confirm the current user actually has a value: list this user's secrets for the company and check secretId is present.
- If absent, create the value first (the create/upsert path), then patch it.
- Never assume a shared secretId works across users - values are per-owner.
- After any user secret deletion, refresh the local list before further edits.
Example fix
// before
await api.patch(`/api/companies/${companyId}/me/user-secrets/${secretId}`, { value: newValue });
// after
const mine = await api.listMyUserSecrets(companyId);
if (!mine.some((s) => s.id === secretId)) {
await api.createUserSecretValue(companyId, secretId, newValue); // first setValue path
} else {
await api.patch(`/api/companies/${companyId}/me/user-secrets/${secretId}`, { value: newValue });
} Defensive patterns
Strategy: validation
Validate before calling
async function upsertMySecretValue(api: ApiClient, companyId: string, secretId: string, value: unknown) {
const mine = await api.fetch(`/api/companies/${companyId}/me/user-secrets`);
const list = await mine.json();
const has = (Array.isArray(list) ? list : list.items ?? []).some(
(s: { id: string }) => s.id === secretId,
);
if (!has) {
// no value row for this user yet: create first, then patch later
return api.createUserSecretValue(companyId, secretId, value);
}
return api.fetch(`/api/companies/${companyId}/me/user-secrets/${secretId}`, {
method: 'PATCH',
body: JSON.stringify({ value }),
});
} Type guard
function isApiErrorBody(body: unknown): body is { error: string } {
return typeof body === 'object' && body !== null &&
typeof (body as Record<string, unknown>).error === 'string';
}
const isValueNotFound = (b: unknown): boolean =>
isApiErrorBody(b) && b.error === 'User secret value not found'; Try / catch
try {
await api.patch(`/api/companies/${companyId}/me/user-secrets/${secretId}`, { value });
} catch (err) {
if (err instanceof ApiError && err.status === 404 && isValueNotFound(err.body)) {
// this user has no value for that id (or it was just deleted): create it
await api.createUserSecretValue(companyId, secretId, value);
return;
}
throw err;
} Prevention
- Remember values are per-user: never reuse a secretId across accounts.
- Refresh 'my secrets' state after any create/delete before further edits.
- In onboarding flows, PUT/POST the value before allowing PATCH-based updates.
- Handle 404 on PATCH as 'create instead', not as a retryable error.
When it happens
Trigger: Patching a secret value the current user never set (definition exists, but this user has no value row); patching after the user removed their value; using someone else's secretId gleaned from logs; :companyId mismatch with where the value was stored.
Common situations: Profile/settings UIs preloading a value that another session just cleared; onboarding flows that PATCH before the initial PUT/POST of the secret value; scripts replaying captured secret IDs across user accounts.
Related errors
- Cannot build API path with an empty path segment.
- Challenge secret is required. Pass --token or --token-env.
- Could not locate local Paperclip skills directory. Expected…
- Environment variable
- Failed to create API key
AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18).
Data as JSON: /api/errors/2c5e71d70a6ae270.
Report an issue: GitHub.
Appendix: source
Thrown at cli/src/commands/client/common.ts:68
opts?: { requireCompany?: boolean },
): ResolvedClientContext {
const context = readContext(options.context);
const { name: profileName, profile } = resolveProfile(context, options.profile);
const apiBase = resolveApiBase(options, profile);
const resolvedApiKey = resolveApiKey(options, profile);
const explicitApiKey = resolvedApiKey.value;
const storedBoardCredential = explicitApiKey ? null : getStoredBoardCredential(apiBase);
const apiKey = explicitApiKey || storedBoardCredential?.token;
const companyId =
options.companyId?.trim() ||
process.env.PAPERCLIP_COMPANY_ID?.trim() ||
profile.companyId;
if (opts?.requireCompany && !companyId) {
throw new Error(
"Company ID is required. Pass --company-id, set PAPERCLIP_COMPANY_ID, or set context profile companyId via `paperclipai context set`.",
);
}
// Agent-authenticated mutations (checkout, release, interactions, PATCH of an
// in-progress issue) require the X-Paperclip-Run-Id header (the server returns
// "401 Agent run id required" without it). Source it from --run-id, else the
// PAPERCLIP_RUN_ID env the adapter/embodiment context already exports.
const runId = options.runId?.trim() || process.env.PAPERCLIP_RUN_ID?.trim() || undefined;
const api = new PaperclipApiClient({
apiBase,
apiKey,
runId,
recoverAuth: explicitApiKey || !canAttemptInteractiveBoardAuth()
? undefined
: async ({ error }) => {
const requestedAccess = error.message.includes("Instance admin required")View on GitHub (pinned to 120ae5428f)