paperclipai/paperclip · error · Error

Decision signing key at ${keyPath} must have permissions 060

Error message

Decision signing key at ${keyPath} must have permissions 0600

What it means

Permission guard in enforceKeyFilePermissions: the key still had group/other bits after a best-effort chmod to 0600. Group/world-readable signing keys would let other local users forge/verify decision signatures, so startup refuses.

Source

Thrown at server/src/services/decision-signing.ts:39

function enforceKeyFilePermissions(keyPath: string) {
  let stats = lstatSync(keyPath);
  if (!stats.isFile()) {
    throw new Error(`Decision signing key at ${keyPath} must be a regular file`);
  }
  assertOwnedByCurrentUser(stats, `Decision signing key at ${keyPath}`);
  if (process.platform === "win32") return;

  const mode = stats.mode & 0o777;
  if ((mode & 0o077) !== 0) {
    chmodSync(keyPath, 0o600);
    stats = lstatSync(keyPath);
    if (!stats.isFile()) {
      throw new Error(`Decision signing key at ${keyPath} must be a regular file`);
    }
    assertOwnedByCurrentUser(stats, `Decision signing key at ${keyPath}`);
    if ((stats.mode & 0o077) !== 0) {
      throw new Error(`Decision signing key at ${keyPath} must have permissions 0600`);
    }
  }
}

function enforceSecretsDirectoryPermissions(directoryPath: string) {
  let stats = lstatSync(directoryPath);
  if (!stats.isDirectory()) {
    throw new Error(`Decision signing secrets directory at ${directoryPath} must be a directory`);
  }
  assertOwnedByCurrentUser(stats, `Decision signing secrets directory at ${directoryPath}`);
  if (process.platform === "win32") return;

  const mode = stats.mode & 0o777;
  if ((mode & 0o077) !== 0) {
    chmodSync(directoryPath, 0o700);
    stats = lstatSync(directoryPath);
    if (!stats.isDirectory()) {
      throw new Error(`Decision signing secrets directory at ${directoryPath} must be a directory`);

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Set permissions to 0600 on the decision signing key: chmod 0600 <keyPath>.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/decision-signing.ts:39 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/11428f30d5c86550. Report an issue: GitHub.