coleam00/Archon · error

MCP config ${serverName}.env must be a JSON object of string

Error message

MCP config ${serverName}.env must be a JSON object of string values (got ${describeJsonType(server.env)})

What it means

If a server entry defines env, it must be a JSON object whose values are strings (each value is env-var interpolated). A non-object env, or an array/null, cannot hold key/value environment variables, so expandEnvVars throws naming the server and the offending type.

Source

Thrown at packages/providers/src/mcp/config.ts:68

function expandEnvVars(
  config: Record<string, unknown>,
  envSource: EnvSource
): {
  expanded: Record<string, unknown>;
  missingVars: string[];
} {
  const result: Record<string, unknown> = {};
  const missingVars: string[] = [];
  for (const [serverName, serverConfig] of Object.entries(config)) {
    if (typeof serverConfig !== 'object' || serverConfig === null || Array.isArray(serverConfig)) {
      throw new Error(
        `MCP server "${serverName}" must be a JSON object (got ${describeJsonType(serverConfig)})`
      );
    }
    const server = { ...(serverConfig as Record<string, unknown>) };
    if (server.env !== undefined) {
      if (typeof server.env !== 'object' || server.env === null || Array.isArray(server.env)) {
        throw new Error(
          `MCP config ${serverName}.env must be a JSON object of string values (got ${describeJsonType(server.env)})`
        );
      }
      server.env = expandEnvVarsInRecord(
        server.env as Record<string, unknown>,
        missingVars,
        envSource,
        `${serverName}.env`
      );
    }
    if (server.headers !== undefined) {
      if (
        typeof server.headers !== 'object' ||
        server.headers === null ||
        Array.isArray(server.headers)
      ) {
        throw new Error(
          `MCP config ${serverName}.headers must be a JSON object of string values (got ${describeJsonType(server.headers)})`

View on GitHub (pinned to 0773b97458)

Solutions

  1. Convert env to an object of strings: {"env": {"DEBUG": "1"}}.
  2. Delete the env key entirely if there are no variables (undefined is allowed).
  3. Split comma or newline separated env strings into individual object entries.

Example fix

// before
{"server": {"command": "node", "env": "DEBUG=1\nLOG=info"}}
// after
{"server": {"command": "node", "env": {"DEBUG": "1", "LOG": "info"}}}
Defensive patterns

Strategy: validation

Validate before calling

const s = cfg[serverName];
if ('env' in s && (typeof s.env !== 'object' || s.env === null || Array.isArray(s.env))) {
  throw new Error(`${serverName}.env must be an object of strings`);
}

Type guard

const isEnvObject = (v: unknown): v is Record<string, string> =>
  typeof v === 'object' && v !== null && !Array.isArray(v) &&
  Object.values(v).every((x) => typeof x === 'string');

Prevention

When it happens

Trigger: loadMcpConfig where a server has "env": "DEBUG=1" (string), "env": ["A=1"] (array), or "env": null instead of an object of strings.

Common situations: Migrating from dotenv-style lines pasted into JSON; YAML-to-JSON conversion producing lists; a script setting env to null when no vars exist; shell export syntax copied verbatim.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/acc5153ed44d4e27. Report an issue: GitHub.