{"record":{"id":"2269065ef77e6dda","repo":"BloopAI/vibe-kanban","slug":"servers-configuration-must-be-an-object","errorCode":null,"errorMessage":"Servers configuration must be an object","messagePattern":"Servers configuration must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/mcpStrategies.ts","lineNumber":49,"sourceCode":"    mcp_config: McpConfig,\n    full_config: JsonValue\n  ): void {\n    let current: JsonValue = full_config;\n    for (const key of mcp_config.servers_path) {\n      if (!isJsonObject(current)) {\n        throw new Error(\n          `Expected object at path: ${mcp_config.servers_path.join('.')}`\n        );\n      }\n      current = current[key];\n      if (current === undefined) {\n        throw new Error(\n          `Missing required field at path: ${mcp_config.servers_path.join('.')}`\n        );\n      }\n    }\n    if (!isJsonObject(current)) {\n      throw new Error('Servers configuration must be an object');\n    }\n  }\n  static extractServersForApi(\n    mcp_config: McpConfig,\n    full_config: JsonValue\n  ): JsonObject {\n    let current: JsonValue = full_config;\n    for (const key of mcp_config.servers_path) {\n      if (!isJsonObject(current)) {\n        throw new Error(\n          `Expected object at path: ${mcp_config.servers_path.join('.')}`\n        );\n      }\n      current = current[key];\n      if (current === undefined) {\n        throw new Error(\n          `Missing required field at path: ${mcp_config.servers_path.join('.')}`\n        );","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/mcpStrategies.ts#L31-L67","documentation":"After walking the full servers_path in validateFullConfig, the final value must be a JSON object of server entries. If it is an array, string, number, boolean, or null, this error is thrown. The servers section exists but has the wrong type.","triggerScenarios":"servers_path resolves to a non-object — e.g. mcp.servers is an array of names instead of an object keyed by server name, or was overwritten by a scalar during a bad edit/merge.","commonSituations":"Hand-editing the config and typing servers as a list; a migration script converting the object to an array; pasting a config snippet from docs that uses a different shape.","solutions":["Reshape the value at servers_path to an object keyed by server name: { \"server-name\": { command, args, ... } }.","Regenerate the section with McpConfigStrategyGeneral.createFullConfig(cfg) using cfg.servers.","Diff the file against a known-good config for this MCP client.","Back up the config before manual edits so you can restore the object shape."],"exampleFix":"// before\n{ \"mcp\": { \"servers\": [\"fetch\", \"fs\"] } } // array -> throws\n// after\n{ \"mcp\": { \"servers\": { \"fetch\": { \"command\": \"uvx\", \"args\": [\"mcp-server-fetch\"] } } } }","handlingStrategy":"validation","validationCode":"function serversSectionIsObject(full, path) {\n  let cur = full;\n  for (const k of path) {\n    if (typeof cur !== 'object' || cur === null || Array.isArray(cur)) return false;\n    cur = cur[k];\n  }\n  return typeof cur === 'object' && cur !== null && !Array.isArray(cur);\n}\nif (!serversSectionIsObject(fullConfig, cfg.servers_path)) console.warn('Servers section must be an object');","typeGuard":"function isServersObject(v: unknown): v is Record<string, Record<string, unknown>> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  McpConfigStrategyGeneral.validateFullConfig(cfg, fullConfig);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Servers configuration must be an object') {\n    fullConfig = McpConfigStrategyGeneral.createFullConfig(cfg); // rewrite from cfg.servers\n  } else throw e;\n}","preventionTips":["Always model MCP servers as an object keyed by server name, never an array","Run validateFullConfig after any external tool or script touches the config","Restore from a known-good backup when the section shape is wrong","Add a config schema test per supported MCP client"],"tags":["config","validation","mcp","type-error"],"backgroundTag":"config-shape-invalid","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}