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
- Normalize the name to a valid slug before building the ID: lowercase, replace invalid characters (`[^a-z0-9.-]`) with `-`, strip leading/trailing dots/hyphens.
- 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.
- If the name came from a registry/config file, re-derive it from parsePluginId on the canonical ID rather than from a display label.
- 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
- Slugify any externally sourced name (lowercase, `[^a-z0-9.-]` → `-`, trim edge dots/hyphens) before building IDs.
- Never build IDs from display labels or user-typed strings without validation.
- Run isValidNameSegment on both segments in a precondition check so failures are attributed correctly.
- Keep plugin `name` fields in marketplace.json lowercase-kebab from the start.
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
- Invalid marketplace name: "${marketplace}"
- Invalid marketplace plugin package name: ${JSON.stringify(na
- Plugin ID exceeds ${MAX_ID_LENGTH} characters: "${id}"
- Invalid skill name "${raw}". Use lowercase letters, digits,
- Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: $
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/06b6aa25611c44d8.
Report an issue: GitHub.