BloopAI/vibe-kanban · error

Expected object at path: ${mcp_config.servers_path.join('.')

Error message

Expected object at path: ${mcp_config.servers_path.join('.')}

What it means

validateFullConfig walks mcp_config.servers_path key-by-key through the full (raw app) config JSON. Before reading each key it asserts the current value is a JSON object; if a mid-path value is an array, string, number, or null it throws this error. It guards against traversing into a non-object when locating the MCP servers section.

Source

Thrown at packages/web-core/src/shared/lib/mcpStrategies.ts:37

        : undefined;
      if (!next) current[key] = {};
      current = current[key] as JsonObject;
    }

    if (cfg.servers_path.length > 0) {
      const lastKey = cfg.servers_path[cfg.servers_path.length - 1];
      current[lastKey] = cfg.servers;
    }
    return fullConfig;
  }
  static validateFullConfig(
    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 {

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Log/print full_config and compare each segment of servers_path against its actual shape.
  2. Fix the config so every segment except the last is a JSON object, or correct servers_path to match the real structure.
  3. If migrating from another tool's config format, use the matching McpConfig strategy rather than reusing servers_path.
  4. Validate the config JSON before calling handleMcpServersChange/handleApplyMcpServers.

Example fix

// before: path points into a scalar
validateFullConfig(cfg, { mcp: 'not-an-object' }); // throws
// after: ensure the container is an object first
const full = { mcp: { servers: {} } };
validateFullConfig(cfg, full);
Defensive patterns

Strategy: validation

Validate before calling

function pathIsTraversable(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 true;
}
if (!pathIsTraversable(fullConfig, cfg.servers_path)) console.warn('Config not traversable at', cfg.servers_path.join('.'));

Type guard

function isJsonObject(v: unknown): v is 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.startsWith('Expected object at path')) {
    fullConfig = McpConfigStrategyGeneral.createFullConfig(cfg); // rebuild
  } else throw e;
}

Prevention

When it happens

Trigger: servers_path contains a key whose current value is not an object — e.g. path ['mcp','servers'] but full_config.mcp is a string/number/boolean/array/null; a user hand-edited the config file so a path segment holds a scalar.

Common situations: A config for one MCP strategy (e.g. a 'mcpServers' object path) applied to a config file shaped for another tool; manual edits corrupting the file; a template that defines a segment as an array.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/60fe45f2afedac0c. Report an issue: GitHub.