{"record":{"id":"eeb584617a0a1a8e","repo":"moeru-ai/airi","slug":"errors-empty-command","errorCode":null,"errorMessage":"errors.empty-command","messagePattern":"errors\\.empty-command","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/renderer/pages/settings/modules/mcp-config.ts","lineNumber":102,"sourceCode":"\n/** Builds the persisted MCP config file from editable rows. */\nexport function buildConfigFile(\n  servers: ServerForm[],\n  translateMessage: TranslateMcpMessage,\n): ElectronMcpStdioConfigFile {\n  const config: ElectronMcpStdioConfigFile = { mcpServers: {} }\n  const seenIdentifiers = new Set<string>()\n\n  for (const [index, server] of servers.entries()) {\n    const identifier = server.identifier.trim()\n    if (!identifier)\n      throw new Error(translateMessage('errors.empty-identifier', { index: index + 1 }))\n\n    if (seenIdentifiers.has(identifier))\n      throw new Error(translateMessage('errors.duplicate-identifier', { name: identifier }))\n\n    if (!server.command.trim())\n      throw new Error(translateMessage('errors.empty-command', { name: identifier }))\n\n    seenIdentifiers.add(identifier)\n    config.mcpServers[identifier] = buildServerConfig(server)\n  }\n\n  return config\n}\n\n/** Builds the JSON editor draft while preserving the current draft when form validation fails. */\nexport function syncJsonDraftFromServers(\n  servers: ServerForm[],\n  previousDraft: string,\n  translateMessage: TranslateMcpMessage,\n  formatError: (error: unknown) => string,\n) {\n  try {\n    return {\n      draft: `${JSON.stringify(buildConfigFile(servers, translateMessage), null, 2)}\\n`,","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/renderer/pages/settings/modules/mcp-config.ts#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function allServersHaveCommand(servers: ServerForm[]): boolean {\n  return servers.every(s => s.command.trim().length > 0)\n}","typeGuard":"function hasNonEmptyCommand(server: ServerForm): boolean {\n  return typeof server.command === 'string' && server.command.trim().length > 0\n}","tryCatchPattern":"try {\n  buildConfigFile(servers, t)\n} catch (e) {\n  // point the user to the row missing a command\n}","preventionTips":["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."],"tags":["mcp","form-validation","i18n","configuration"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}