paperclipai/paperclip · error · Error

Failed to create board API key

Error message

Failed to create board API key

What it means

Thrown by the `board create` action in token.ts when ctx.api.post to /api/board-api-keys returns a falsy value. Mirrors error 122 but for board-scope keys: the server must return a CreatedBoardKey object; an empty or unparseable body trips the guard.

Source

Thrown at cli/src/commands/client/token.ts:162

    board
      .command("create")
      .description("Create a named board API key")
      .option("-C, --company-id <id>", "Company ID used for audit context")
      .option("--name <name>", "API key label", "cli-board")
      .option("--expires-at <iso8601>", "Expiration timestamp")
      .option("--ttl-days <days>", "Expiration in days from now")
      .option("--never-expires", "Create a non-expiring key")
      .action(async (opts: BoardTokenOptions) => {
        try {
          const ctx = resolveCommandContext(opts);
          const expiresAt = resolveBoardKeyExpiresAt(opts);
          const payload = createBoardApiKeySchema.parse({
            name: opts.name,
            requestedCompanyId: opts.companyId ?? ctx.companyId ?? null,
            expiresAt,
          });
          const key = await ctx.api.post<CreatedBoardKey>("/api/board-api-keys", payload);
          if (!key) throw new Error("Failed to create board API key");
          printOutput({ key }, { json: ctx.json });
        } catch (err) {
          handleCommandError(err);
        }
      }),
    { includeCompany: false },
  );

  addCommonClientOptions(
    board
      .command("list")
      .description("List board API keys for the current board user")
      .action(async (opts: BaseClientOptions) => {
        try {
          const ctx = resolveCommandContext(opts);
          const keys = (await ctx.api.get<BoardKeyRow[]>("/api/board-api-keys")) ?? [];
          if (ctx.json) {
            printOutput(keys, { json: true });

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Confirm board-api-keys POST returns a non-empty JSON body via curl.
  2. Align CLI and server versions.
  3. Check the API base URL and auth header are correct.
  4. Enable CLI debug output to see the raw response.

Example fix

// before: board-api-keys POST returns '' or {}
// after: server returns the created key
res.status(201).json({ id, key, name, expiresAt });
Defensive patterns

Strategy: try-catch

Type guard

function isCreatedBoardKey(value: unknown): value is CreatedBoardKey {
  return !!value && typeof value === "object" && "key" in value && typeof (value as any).key === "string";
}

Try / catch

try {
  const key = await ctx.api.post<CreatedBoardKey>("/api/board-api-keys", payload);
  if (!isCreatedBoardKey(key)) throw new Error("Server returned no board key body");
} catch (err) {
  handleCommandError(err);
}

Prevention

When it happens

Trigger: Calling `paperclipai ... token board create ...` and the server returns an empty 2xx body, or the API client resolves null because the JSON did not match the expected shape.

Common situations: API/CLI version skew, a proxy stripping the response body, schema validator on the client rejecting the body and resolving null, or a misconfigured base URL.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/a7cc91d4f5949656. Report an issue: GitHub.