BloopAI/vibe-kanban · error
Servers configuration must be an object
Error message
Servers configuration must be an object
What it means
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.
Source
Thrown at packages/web-core/src/shared/lib/mcpStrategies.ts:49
mcp_config: McpConfig,
full_config: JsonValue
): void {
let current: JsonValue = full_config;
for (const key of mcp_config.servers_path) {
if (!isJsonObject(current)) {
throw new Error(
`Expected object at path: ${mcp_config.servers_path.join('.')}`
);
}
current = current[key];
if (current === undefined) {
throw new Error(
`Missing required field at path: ${mcp_config.servers_path.join('.')}`
);
}
}
if (!isJsonObject(current)) {
throw new Error('Servers configuration must be an object');
}
}
static extractServersForApi(
mcp_config: McpConfig,
full_config: JsonValue
): JsonObject {
let current: JsonValue = full_config;
for (const key of mcp_config.servers_path) {
if (!isJsonObject(current)) {
throw new Error(
`Expected object at path: ${mcp_config.servers_path.join('.')}`
);
}
current = current[key];
if (current === undefined) {
throw new Error(
`Missing required field at path: ${mcp_config.servers_path.join('.')}`
);View on GitHub (pinned to 4deb7eca8f)
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.
Example fix
// before
{ "mcp": { "servers": ["fetch", "fs"] } } // array -> throws
// after
{ "mcp": { "servers": { "fetch": { "command": "uvx", "args": ["mcp-server-fetch"] } } } } Defensive patterns
Strategy: validation
Validate before calling
function serversSectionIsObject(full, path) {
let cur = full;
for (const k of path) {
if (typeof cur !== 'object' || cur === null || Array.isArray(cur)) return false;
cur = cur[k];
}
return typeof cur === 'object' && cur !== null && !Array.isArray(cur);
}
if (!serversSectionIsObject(fullConfig, cfg.servers_path)) console.warn('Servers section must be an object'); Type guard
function isServersObject(v: unknown): v is Record<string, Record<string, unknown>> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try {
McpConfigStrategyGeneral.validateFullConfig(cfg, fullConfig);
} catch (e) {
if (e instanceof Error && e.message === 'Servers configuration must be an object') {
fullConfig = McpConfigStrategyGeneral.createFullConfig(cfg); // rewrite from cfg.servers
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Expected object at path: ${mcp_config.servers_path.join('.')
- Missing required field at path: ${mcp_config.servers_path.jo
- Unknown preconfigured server '${serverKey}'
- Provide `prompt`, or `issue_id` that has a non-empty title/d
- Failed to list projects (${res.status})
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/2269065ef77e6dda.
Report an issue: GitHub.