JuliusBrussee/caveman · error

project name must contain a letter or number

Error message

project name must contain a letter or number

What it means

safeName lowercases the project name, collapses every run of characters outside [a-z0-9_-] into '-', trims leading/trailing dashes, and then requires a non-empty result. A name made entirely of symbols/spaces/unicode (e.g. '---', '日本語', '!!!') normalizes to the empty string, which cannot serve as a package/directory name, so it throws.

Source

Thrown at packages/create-caveman-agent/src/index.ts:307

`,
  };
}

function credentialName(provider: Provider): string {
  if (provider === "anthropic") return "ANTHROPIC_API_KEY";
  if (provider === "openai") return "OPENAI_API_KEY";
  return "GEMINI_API_KEY (or GOOGLE_API_KEY)";
}

function parseProvider(value: string): Provider {
  const normalized = value.trim().toLowerCase();
  if (normalized === "anthropic" || normalized === "openai" || normalized === "google") return normalized;
  throw new Error(`unsupported provider ${JSON.stringify(value)}`);
}

function safeName(value: string): string {
  const normalized = value.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
  if (!normalized) throw new Error("project name must contain a letter or number");
  return normalized.slice(0, 96);
}

async function assertAbsent(path: string): Promise<void> {
  try {
    await stat(path);
    throw new Error(`target already exists: ${path}`);
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
  }
}

main().catch((error) => {
  const message = error instanceof Error ? error.message : String(error);
  process.stderr.write(`create-caveman-agent: ${message}\n`);
  process.exitCode = 1;
});

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Choose a name containing at least one ASCII letter or digit (other characters become separators).
  2. For non-English names, add a Latin prefix/suffix, e.g. `日本語-app` → normalizes to `-app` → trimmed to `app`; prefer `nihongo-app`.
  3. Keep the final name under the 96-char cap applied after normalization.

Example fix

# before
npm create @caveman-ai/agent@latest "🚀!!!"
# after
npm create @caveman-ai/agent@latest rocket-app
Defensive patterns

Strategy: validation

Validate before calling

function normalizesToNonEmpty(name: string): boolean {
  const n = name.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
  return n.length > 0;
}

Prevention

When it happens

Trigger: Passing a target like `--`, `...`, `©©`, or any name whose lowercase form contains no ASCII letters, digits, underscore, or hyphen.

Common situations: Non-Latin project names, accidental shell expansions producing punctuation, paste of emoji/decorative names, or a name of only dots that collapses to nothing.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/6f0d78eb5fc70cca. Report an issue: GitHub.