moeru-ai/airi · error · Error
errors.empty-command
Error message
errors.empty-command
What it means
Thrown by buildConfigFile when a server row has a valid, unique identifier but its command field (after trim) is empty. translateMessage('errors.empty-command', { name }) resolves the locale string; note the message key itself is the thrown text shown here — the resolved translation is what the user sees. An MCP stdio server requires a command to spawn.
Source
Thrown at apps/stage-tamagotchi/src/renderer/pages/settings/modules/mcp-config.ts:102
/** Builds the persisted MCP config file from editable rows. */
export function buildConfigFile(
servers: ServerForm[],
translateMessage: TranslateMcpMessage,
): ElectronMcpStdioConfigFile {
const config: ElectronMcpStdioConfigFile = { mcpServers: {} }
const seenIdentifiers = new Set<string>()
for (const [index, server] of servers.entries()) {
const identifier = server.identifier.trim()
if (!identifier)
throw new Error(translateMessage('errors.empty-identifier', { index: index + 1 }))
if (seenIdentifiers.has(identifier))
throw new Error(translateMessage('errors.duplicate-identifier', { name: identifier }))
if (!server.command.trim())
throw new Error(translateMessage('errors.empty-command', { name: identifier }))
seenIdentifiers.add(identifier)
config.mcpServers[identifier] = buildServerConfig(server)
}
return config
}
/** Builds the JSON editor draft while preserving the current draft when form validation fails. */
export function syncJsonDraftFromServers(
servers: ServerForm[],
previousDraft: string,
translateMessage: TranslateMcpMessage,
formatError: (error: unknown) => string,
) {
try {
return {
draft: `${JSON.stringify(buildConfigFile(servers, translateMessage), null, 2)}\n`,View on GitHub (pinned to 27111382b4)
Solutions
- Enter the executable command for the server (e.g. 'npx', 'node', '/usr/local/bin/mcp-server').
- If the server is HTTP/SSE-based, use the appropriate transport config rather than the stdio form.
- Validate the command field is non-empty before enabling Save.
Defensive patterns
Strategy: validation
Validate before calling
function allServersHaveCommand(servers: ServerForm[]): boolean {
return servers.every(s => s.command.trim().length > 0)
} Type guard
function hasNonEmptyCommand(server: ServerForm): boolean {
return typeof server.command === 'string' && server.command.trim().length > 0
} Try / catch
try {
buildConfigFile(servers, t)
} catch (e) {
// point the user to the row missing a command
} Prevention
- Disable Save until every row has a non-empty command.
- For non-stdio transports, route to the correct transport form.
- Trim and validate command fields reactively.
When it happens
Trigger: User filled in a server name but left the command/executable blank, or entered only args/env without the binary path. The config object is built only after all three checks (identifier, duplicate, command) pass.
Common situations: User intended to use a URL/transport-based server but the form is stdio-only; command field cleared during editing; mis-pasted config omitted the command.
Related errors
- Server # {index} is missing an identifier.
- Identifier "{name}" is used more than once — names need to b
- Invalid remote debug port: ${env.APP_REMOTE_DEBUG_PORT}
- No reachable private LAN address is available for the curren
- Failed to apply server channel configuration
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/eeb584617a0a1a8e.
Report an issue: GitHub.