paperclipai/paperclip · error · Error
Decision signing secrets directory at ${directoryPath} must
Error message
Decision signing secrets directory at ${directoryPath} must have permissions 0700 What it means
Permission guard in enforceSecretsDirectoryPermissions: the directory still exposes group/other bits after a best-effort chmod to 0700. A looser directory would let other local users list/replace secret files inside, so startup refuses.
Source
Thrown at server/src/services/decision-signing.ts:61
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`);
}
assertOwnedByCurrentUser(stats, `Decision signing secrets directory at ${directoryPath}`);
if ((stats.mode & 0o077) !== 0) {
throw new Error(`Decision signing secrets directory at ${directoryPath} must have permissions 0700`);
}
}
}
function readGeneratedSecret(keyPath: string): string {
enforceKeyFilePermissions(keyPath);
const existing = readFileSync(keyPath, "utf8").trim();
if (existing.length < MIN_SECRET_LENGTH) {
throw new Error(
`Invalid decision signing key at ${keyPath} (must be at least ${MIN_SECRET_LENGTH} characters); remove the file to regenerate it or set PAPERCLIP_DECISION_SIGNING_SECRET`,
);
}
return existing;
}
function isAlreadyExists(error: unknown) {
return (error as NodeJS.ErrnoException).code === "EEXIST";
}View on GitHub (pinned to 120ae5428f)
Solutions
- Set permissions to 0700 on the secrets directory: chmod 0700 <directoryPath>.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/src/services/decision-signing.ts:61 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/1adc277107cc04fa.
Report an issue: GitHub.