can1357/oh-my-pi · error · Error

Invalid plugin name: "${name}"

Error message

Invalid plugin name: "${name}"

What it means

buildPluginId constructs canonical plugin IDs of the form `"name@marketplace"` and validates both segments with isValidNameSegment: 1–64 chars, lowercase alphanumerics with internal dots and hyphens only (must start and end with [a-z0-9]). This throw means the plugin name segment failed that pattern — empty, too long, uppercase, or containing disallowed characters such as `@`, `_`, spaces, or a leading/trailing dot or hyphen.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/types.ts:26

 * The installed registry MUST pass `parseClaudePluginsRegistry()` validation —
 * it uses `version: 2` (numeric) and `plugins: Record<string, ...[]>`.
 */

// ── Plugin ID helpers ────────────────────────────────────────────────

const NAME_RE = /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/;
const MAX_NAME_LENGTH = 64;
const MAX_ID_LENGTH = 128;

/** Validate a plugin or marketplace name segment. */
export function isValidNameSegment(s: string): boolean {
	return s.length > 0 && s.length <= MAX_NAME_LENGTH && NAME_RE.test(s);
}

/** Build canonical plugin ID: `"name@marketplace"`. Both segments are validated. */
export function buildPluginId(name: string, marketplace: string): string {
	if (!isValidNameSegment(name)) {
		throw new Error(`Invalid plugin name: "${name}"`);
	}
	if (!isValidNameSegment(marketplace)) {
		throw new Error(`Invalid marketplace name: "${marketplace}"`);
	}
	const id = `${name}@${marketplace}`;
	if (id.length > MAX_ID_LENGTH) {
		throw new Error(`Plugin ID exceeds ${MAX_ID_LENGTH} characters: "${id}"`);
	}
	return id;
}

/** Parse `"name@marketplace"` → `{ name, marketplace }` or `null`. */
export function parsePluginId(id: string): { name: string; marketplace: string } | null {
	const atIndex = id.lastIndexOf("@");
	if (atIndex <= 0 || atIndex === id.length - 1) return null;

	const name = id.slice(0, atIndex);
	const marketplace = id.slice(atIndex + 1);

View on GitHub (pinned to 9690622007)

Solutions

  1. Normalize the name to a valid slug before building the ID: lowercase, replace invalid characters (`[^a-z0-9.-]`) with `-`, strip leading/trailing dots/hyphens.
  2. Fix the plugin's `name` in the marketplace.json source catalog to match /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/ and ≤64 chars.
  3. If the name came from a registry/config file, re-derive it from parsePluginId on the canonical ID rather than from a display label.
  4. Validate with isValidNameSegment(name) before calling buildPluginId and surface a friendly message instead of the raw throw.

Example fix

// before
const id = buildPluginId(rawName, market); // rawName = "My_Tool"
// after
const slug = rawName.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/^[.-]+|[.-]+$/g, "");
const id = buildPluginId(slug, market);
Defensive patterns

Strategy: validation

Validate before calling

import { isValidNameSegment } from "@oh-my-pi/pi-coding-agent/.../marketplace/types";
if (!isValidNameSegment(name)) {
	throw new Error(`Plugin name must match /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/ and be 1-64 chars: "${name}"`);
}

Type guard

function isPluginName(v: unknown): v is string {
	return typeof v === "string" && /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/.test(v) && v.length <= 64;
}

Try / catch

let id: string;
try {
	id = buildPluginId(name, marketplace);
} catch (err) {
	if (err instanceof Error && err.message.startsWith('Invalid plugin name')) {
		id = buildPluginId(slugify(name), marketplace);
	} else throw err;
}

Prevention

When it happens

Trigger: Calling buildPluginId(name, marketplace) (or its wrappers pluginId/id/id1/id2) with a name that is empty, longer than 64 characters, contains uppercase letters, underscores, `@`, spaces, slashes, or begins/ends with `.` or `-` — typically when generating an ID from an untrusted marketplace.json plugin entry.

Common situations: A marketplace catalog lists a plugin named `My_Plugin` or `my-tool-` (trailing hyphen); code builds an ID from a user-typed plugin name instead of the validated slug; automation derives names from GitHub repo names containing uppercase or underscores; empty name after a failed split/trim.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/06b6aa25611c44d8. Report an issue: GitHub.