paperclipai/paperclip · error · Error

Invalid PAPERCLIP_PAGE_DEFAULT_PREFIX: use lowercase path…

Error message

Invalid PAPERCLIP_PAGE_DEFAULT_PREFIX: use lowercase path segments without leading or trailing slashes

What it means

announcementPublishPrefix validates the optional PAPERCLIP_PAGE_DEFAULT_PREFIX host prefix against /^[a-z0-9-]+(?:\/[a-z0-9-]+)*$/ — lowercase alphanumeric-and-hyphen segments separated by single slashes, with no leading or trailing slash. An invalid value throws this error before any publishing happens.

Solutions

  1. Rewrite the prefix as lowercase path segments, e.g. 'pages/team-a' instead of '/Pages/Team-A/'.
  2. Remove leading and trailing slashes from the env value.
  3. Replace invalid characters (underscores, dots, spaces) with hyphens.
  4. Leave PAPERCLIP_PAGE_DEFAULT_PREFIX unset to use the default 'announcements/v1' prefix.

Example fix

// before
PAPERCLIP_PAGE_DEFAULT_PREFIX=/Announcements/
// after
PAPERCLIP_PAGE_DEFAULT_PREFIX=announcements
Defensive patterns

Strategy: validation

Validate before calling

const prefix = process.env.PAPERCLIP_PAGE_DEFAULT_PREFIX;
if (prefix !== undefined && !/^[a-z0-9-]+(?:\/[a-z0-9-]+)*$/.test(prefix)) {
  throw new Error(`Bad PAPERCLIP_PAGE_DEFAULT_PREFIX: ${prefix}`);
}

Type guard

const isValidPrefix = (p) => p === undefined || /^[a-z0-9-]+(?:\/[a-z0-9-]+)*$/.test(p);

Try / catch

try {
  const prefix = announcementPublishPrefix(staging, hostPrefix);
} catch (e) {
  if (String(e.message).includes('PAPERCLIP_PAGE_DEFAULT_PREFIX')) {
    console.error('Fix the env var: lowercase [a-z0-9-] segments, no leading/trailing slashes.');
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling announcementPublishPrefix (or the publish-announcements CLI) with hostPrefix containing uppercase letters, underscores, dots, leading/trailing slashes, empty segments ('//'), or other characters outside [a-z0-9-].

Common situations: Setting PAPERCLIP_PAGE_DEFAULT_PREFIX='/announcements' or 'My/Prefix' in CI secrets or .env; copying a URL with scheme into the prefix; using a trailing slash out of habit.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/4bb7cdf71df84535. Report an issue: GitHub.

Appendix: source

Thrown at scripts/publish-announcements.ts:13

#!/usr/bin/env -S node --import tsx
import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { lstat, readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { ANNOUNCEMENT_ANIMATION_MAX_BYTES, ANNOUNCEMENT_IMAGE_MAX_BYTES, ANNOUNCEMENT_MANIFEST_MAX_BYTES, announcementIdSchema, announcementManifestSchema } from "../packages/shared/src/announcements.js";

import { validateAnnouncementAnimation } from "../server/src/services/announcement-animation.js";

export function announcementPublishPrefix(staging?: string, hostPrefix?: string) {
  if (hostPrefix !== undefined && !/^[a-z0-9-]+(?:\/[a-z0-9-]+)*$/.test(hostPrefix)) {
    throw new Error("Invalid PAPERCLIP_PAGE_DEFAULT_PREFIX: use lowercase path segments without leading or trailing slashes");
  }
  const prefix = staging === undefined ? "announcements/v1" : `announcements/staging/${announcementIdSchema.parse(staging)}/v1`;
  return hostPrefix ? `${hostPrefix}/${prefix}` : prefix;
}

export function parseAnnouncementPublishArgs(args: string[]) {
  let sourceDirectory: string | undefined;
  let staging: string | undefined;
  let mode: "publish" | "dry-run" | undefined;
  const usage = "Usage: publish-announcements.ts [directory] [--staging name] [--dry-run | --publish]";
  for (let index = 0; index < args.length; index++) {
    const arg = args[index];
    if (arg === "--publish" || arg === "--dry-run") {
      if (mode) throw new Error(usage);
      mode = arg === "--publish" ? "publish" : "dry-run";
    } else if (arg === "--staging") {
      if (staging !== undefined || !args[index + 1]) throw new Error(usage);
      staging = announcementIdSchema.parse(args[++index]);

View on GitHub (pinned to 3f1d897a7c)