paperclipai/paperclip · error · Error

Invalid plugin name. Must be lowercase and may include scope

Error message

Invalid plugin name. Must be lowercase and may include scope, dots, underscores, or hyphens.

What it means

scaffoldPluginProject validates options.pluginName with isValidPluginName, which requires either an unscoped lowercase name matching /^[a-z0-9._-]+$/ or a scoped name matching /^@[a-z0-9_-]+\/[a-z0-9._-]+$/. Uppercase, spaces, slashes in the wrong place, or other punctuation are rejected.

Source

Thrown at packages/plugins/create-paperclip-plugin/src/index.ts:130

  }

  return tarballPath;
}

/**
 * Generate a complete Paperclip plugin starter project.
 *
 * Output includes manifest/worker/UI entries, SDK harness tests, bundler presets,
 * and a local dev server script for hot-reload workflow.
 */
export function scaffoldPluginProject(options: ScaffoldPluginOptions): string {
  const template = options.template ?? "default";
  if (!VALID_TEMPLATES.includes(template)) {
    throw new Error(`Invalid template '${template}'. Expected one of: ${VALID_TEMPLATES.join(", ")}`);
  }

  if (!isValidPluginName(options.pluginName)) {
    throw new Error("Invalid plugin name. Must be lowercase and may include scope, dots, underscores, or hyphens.");
  }

  if (options.category && !VALID_CATEGORIES.has(options.category)) {
    throw new Error(`Invalid category '${options.category}'. Expected one of: ${[...VALID_CATEGORIES].join(", ")}`);
  }

  const outputDir = path.resolve(options.outputDir);
  if (fs.existsSync(outputDir)) {
    throw new Error(`Directory already exists: ${outputDir}`);
  }

  const displayName = options.displayName ?? makeDisplayName(options.pluginName);
  const description = options.description ?? "A Paperclip plugin";
  const author = options.author ?? "Plugin Author";
  const category = options.category ?? (template === "workspace" ? "workspace" : template === "environment" ? "environment" : "connector");
  const manifestId = packageToManifestId(options.pluginName);
  const localSdkPath = path.resolve(options.sdkPath ?? getLocalSdkPackagePath());
  const localSharedPath = getLocalSharedPackagePath(localSdkPath);

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Lowercase the name and restrict to letters, digits, '.', '_', '-'.
  2. For a scoped plugin use the form '@scope/name' with both halves lowercase.
  3. Set the human-readable name via options.displayName instead of pluginName.

Example fix

// before
scaffoldPluginProject({ pluginName: 'My Cool Plugin' })
// after
scaffoldPluginProject({ pluginName: 'my-cool-plugin', displayName: 'My Cool Plugin' })
Defensive patterns

Strategy: type-guard

Validate before calling

import { isValidPluginName } from '@paperclip/create-paperclip-plugin';
if (!isValidPluginName(name)) throw new Error('plugin name must be lowercase [a-z0-9._-] or @scope/name');

Type guard

function isValidPluginNameCandidate(name: string): boolean {
  return /^@[a-z0-9_-]+\/[a-z0-9._-]+$/.test(name) || /^[a-z0-9._-]+$/.test(name);
}

Prevention

When it happens

Trigger: Passing a plugin name with uppercase letters, spaces, leading '@' without a slash, multiple slashes, or characters outside [a-z0-9._-]. Examples that fail: 'MyPlugin', 'foo bar', '@Scope/Foo', 'foo+v2', 'foo/bar'.

Common situations: User supplies a human-readable display name where the package name is expected; mixed-case org/scope; illegal npm characters copied from a non-npm context.

Related errors


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