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.
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
- Missing required field at path
- Unknown preconfigured server
- Provide `prompt`, or `issue_id` that has a non-empty…
- Action " " requires a workspace target
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/2269065ef77e6dda.
Report an issue: GitHub.
Appendix: 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)