coleam00/Archon · error

MCP config ${fieldPath}.${key} must be a string (got ${descr

Error message

MCP config ${fieldPath}.${key} must be a string (got ${describeJsonType(val)})

What it means

While expanding environment-variable references in an MCP server's env or headers record, the library requires every value to be a plain string. A non-string value (number, boolean, null, array, object) makes interpolation impossible, so expandEnvVarsInRecord throws with the exact field path and the JSON type it found. Missing variables are tolerated (collected in missingVars), but wrong types are not.

Source

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

  if (value === null) return 'null';
  if (Array.isArray(value)) return 'array';
  return typeof value;
}

/**
 * Expand $VAR_NAME and ${VAR_NAME} references in string-valued records from
 * the supplied environment source.
 */
function expandEnvVarsInRecord(
  record: Record<string, unknown>,
  missingVars: string[],
  envSource: EnvSource,
  fieldPath: string
): Record<string, string> {
  const result: Record<string, string> = {};
  for (const [key, val] of Object.entries(record)) {
    if (typeof val !== 'string') {
      throw new Error(
        `MCP config ${fieldPath}.${key} must be a string (got ${describeJsonType(val)})`
      );
    }
    result[key] = val.replace(
      /\$(?:\{([A-Z_][A-Z0-9_]*)\}|([A-Z_][A-Z0-9_]*))/g,
      (_, braced: string | undefined, bare: string | undefined) => {
        const varName = braced ?? bare ?? '';
        const envVal = envSource[varName];
        if (envVal === undefined) {
          missingVars.push(varName);
        }
        return envVal ?? '';
      }
    );
  }
  return result;
}

View on GitHub (pinned to 0773b97458)

Solutions

  1. Quote the offending value as a string in the config: true -> "true", 3 -> "3".
  2. Move non-string data out of env/headers into a config key the server accepts natively.
  3. Validate the JSON config with a schema (e.g. zod: Record<string,string>) before loading.

Example fix

// before
{"env": {"DEBUG": true, "PORT": 8080}}
// after
{"env": {"DEBUG": "true", "PORT": "8080"}}
Defensive patterns

Strategy: validation

Validate before calling

function assertStringRecord(env: unknown, path: string): asserts env is Record<string, string> {
  if (typeof env !== 'object' || env === null || Array.isArray(env) ||
      !Object.values(env).every((v) => typeof v === 'string')) {
    throw new Error(`${path} must be an object of string values`);
  }
}
// before loadMcpConfig: for each server in parsed config, assertStringRecord(server.env, `${name}.env`)

Type guard

const isStringRecord = (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: Calling loadMcpConfig on a JSON config where a server's env or headers entry has a non-string value, e.g. {"env": {"DEBUG": true}} or {"headers": {"X-Retries": 3}}.

Common situations: Hand-editing a config with numeric flags or booleans; copying a Docker/CLI env format that allows integers; a tool exporting env with structured values; JSON schema drift after editing by script.

Related errors


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