can1357/oh-my-pi · error

Host tool at index ${index} must provide a non-empty name

Error message

Host tool at index ${index} must provide a non-empty name

What it means

normalizeHostToolDefinitions validates each host-provided tool before registering it with the agent. The tool's name must be a string that is non-empty after trimming; otherwise this error is thrown with the tool's array index. It ensures every host tool has an identifier usable for dispatch.

Source

Thrown at packages/coding-agent/src/modes/rpc/rpc-mode.ts:501

			const cancelled = !(await session.switchSession(command.sessionPath));
			if (!cancelled) subagentRegistry?.clear();
			return { type: "switch_session", data: { cancelled } };
		}

		case "branch": {
			const result = await session.branch(command.entryId);
			if (!result.cancelled) subagentRegistry?.clear();
			return { type: "branch", data: { text: result.selectedText, cancelled: result.cancelled } };
		}
	}
	throw new Error("Unsupported RPC session change command");
}

function normalizeHostToolDefinitions(tools: RpcHostToolDefinition[]): RpcHostToolDefinition[] {
	return tools.map((tool, index) => {
		const name = typeof tool.name === "string" ? tool.name.trim() : "";
		if (!name) {
			throw new Error(`Host tool at index ${index} must provide a non-empty name`);
		}
		const description = typeof tool.description === "string" ? tool.description.trim() : "";
		if (!description) {
			throw new Error(`Host tool "${name}" must provide a non-empty description`);
		}
		if (!tool.parameters || typeof tool.parameters !== "object" || Array.isArray(tool.parameters)) {
			throw new Error(`Host tool "${name}" must provide a JSON Schema object`);
		}
		const label = typeof tool.label === "string" && tool.label.trim() ? tool.label.trim() : name;
		return {
			name,
			label,
			description,
			parameters: tool.parameters,
			hidden: tool.hidden === true,
			loadMode: defaultLoadModeForToolName(name, tool.loadMode),
		};
	});

View on GitHub (pinned to 9690622007)

Solutions

  1. Set a non-empty 'name' string on the tool entry at the reported index.
  2. If names are generated, validate/trim them before passing the array and drop or repair entries with empty names.
  3. Fix config key casing so the name field is actually read (e.g. 'name' not 'Name').

Example fix

// before
const tools = [{ description: "Run a shell command", parameters: { type: "object" } }];
// after
const tools = [{ name: "run_shell", description: "Run a shell command", parameters: { type: "object" } }];
Defensive patterns

Strategy: validation

Validate before calling

tools.forEach((t, i) => {
  if (typeof t.name !== "string" || !t.name.trim()) throw new Error(`Tool at index ${i} missing non-empty name`);
});

Type guard

function hasValidName(t: { name: unknown }): t is { name: string } {
  return typeof t.name === "string" && t.name.trim().length > 0;
}

Try / catch

try {
  rpc.registerHostTools(tools);
} catch (err) {
  if (err instanceof Error && /must provide a non-empty name/.test(err.message)) {
    logger.warn("skipping host tool with empty name", { err });
  } else throw err;
}

Prevention

When it happens

Trigger: Registering host tools via the tools option with an entry whose name is undefined, an empty string, whitespace-only, or a non-string (e.g. a number or null).

Common situations: Programmatic tool list generation where one entry's name field is omitted or built from an empty variable; JSON configs where 'name' was misspelled so it defaults to undefined.

Related errors


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