can1357/oh-my-pi · error · Error

package.json must have a name field

Error message

package.json must have a name field

What it means

After successfully reading package.json, PluginManager requires a non-empty "name" field because the name is used to compute the node_modules link path (getPluginsNodeModules()/pkg.name) and as the plugin's registry key. A package.json without a name (or with an empty one) is rejected before any linking happens.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/manager.ts:783

		return plugins;
	}

	/**
	 * Link a local plugin for development.
	 */
	async link(localPath: string): Promise<InstalledPlugin> {
		const absolutePath = path.resolve(this.#cwd, localPath);

		const pkgFilePath = path.join(absolutePath, "package.json");
		let pkg: { name?: string; version: string; omp?: PluginManifest; pi?: PluginManifest };
		try {
			pkg = await Bun.file(pkgFilePath).json();
		} catch (err) {
			if (isEnoent(err)) throw new Error(`package.json not found at ${absolutePath}`);
			throw err;
		}
		if (!pkg.name) {
			throw new Error("package.json must have a name field");
		}

		await this.#ensurePluginsDir();

		const linkPath = path.join(getPluginsNodeModules(), pkg.name);

		// Handle scoped packages
		if (pkg.name.startsWith("@")) {
			const scopeDir = path.join(getPluginsNodeModules(), pkg.name.split("/")[0]);
			await fs.promises.mkdir(scopeDir, { recursive: true });
		}

		// Remove existing
		try {
			const stats = await fs.promises.lstat(linkPath);
			if (stats.isSymbolicLink() || stats.isDirectory()) {
				await fs.promises.unlink(linkPath);
			}

View on GitHub (pinned to 9690622007)

Solutions

  1. Add a "name" field to the plugin's package.json (lowercase, npm-valid).
  2. Ensure the name is non-empty and unique among installed plugins.
  3. Regenerate the package.json with a proper scaffolding tool if it was hand-written.
  4. If the file is not meant to be a plugin package, move the omp/pi manifest to the correct plugin descriptor file.

Example fix

// before (package.json)
{ "version": "1.0.0", "omp": { "features": {} } }
// after
{ "name": "my-plugin", "version": "1.0.0", "omp": { "features": {} } }
Defensive patterns

Strategy: validation

Validate before calling

const pkg = await Bun.file(path.join(pluginDir, "package.json")).json();
if (typeof pkg.name !== "string" || pkg.name.length === 0) {
  throw new Error(`${pluginDir}/package.json has no name`);
}

Type guard

function isNamedPackage(pkg: unknown): pkg is { name: string; version: string } {
  return typeof pkg === "object" && pkg !== null &&
    typeof (pkg as { name?: unknown }).name === "string" &&
    (pkg as { name: string }).name.length > 0;
}

Try / catch

try {
  await manager.installFromPath(dir);
} catch (err) {
  if (err instanceof Error && err.message === "package.json must have a name field") {
    console.error("Add a non-empty name to the plugin package.json");
  } else throw err;
}

Prevention

When it happens

Trigger: Installing a plugin whose package.json omits the "name" field or has "name": ""; loading a hand-written or generated package.json used only as a manifest container.

Common situations: Minimal/hand-rolled package.json missing name; a JSON file that parses but is not a real npm package; scripts generating package.json that skip the name field.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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