{"record":{"id":"79dfc7a44ca5eaf0","repo":"coleam00/Archon","slug":"mcp-config-fieldpath-key-must-be-a-string-g","errorCode":null,"errorMessage":"MCP config ${fieldPath}.${key} must be a string (got ${describeJsonType(val)})","messagePattern":"MCP config (.+?)\\.(.+?) must be a string \\(got (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/providers/src/mcp/config.ts","lineNumber":31,"sourceCode":"  if (value === null) return 'null';\n  if (Array.isArray(value)) return 'array';\n  return typeof value;\n}\n\n/**\n * Expand $VAR_NAME and ${VAR_NAME} references in string-valued records from\n * the supplied environment source.\n */\nfunction expandEnvVarsInRecord(\n  record: Record<string, unknown>,\n  missingVars: string[],\n  envSource: EnvSource,\n  fieldPath: string\n): Record<string, string> {\n  const result: Record<string, string> = {};\n  for (const [key, val] of Object.entries(record)) {\n    if (typeof val !== 'string') {\n      throw new Error(\n        `MCP config ${fieldPath}.${key} must be a string (got ${describeJsonType(val)})`\n      );\n    }\n    result[key] = val.replace(\n      /\\$(?:\\{([A-Z_][A-Z0-9_]*)\\}|([A-Z_][A-Z0-9_]*))/g,\n      (_, braced: string | undefined, bare: string | undefined) => {\n        const varName = braced ?? bare ?? '';\n        const envVal = envSource[varName];\n        if (envVal === undefined) {\n          missingVars.push(varName);\n        }\n        return envVal ?? '';\n      }\n    );\n  }\n  return result;\n}\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/providers/src/mcp/config.ts#L13-L49","documentation":"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.","triggerScenarios":"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}}.","commonSituations":"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.","solutions":["Quote the offending value as a string in the config: true -> \"true\", 3 -> \"3\".","Move non-string data out of env/headers into a config key the server accepts natively.","Validate the JSON config with a schema (e.g. zod: Record<string,string>) before loading."],"exampleFix":"// before\n{\"env\": {\"DEBUG\": true, \"PORT\": 8080}}\n// after\n{\"env\": {\"DEBUG\": \"true\", \"PORT\": \"8080\"}}","handlingStrategy":"validation","validationCode":"function assertStringRecord(env: unknown, path: string): asserts env is Record<string, string> {\n  if (typeof env !== 'object' || env === null || Array.isArray(env) ||\n      !Object.values(env).every((v) => typeof v === 'string')) {\n    throw new Error(`${path} must be an object of string values`);\n  }\n}\n// before loadMcpConfig: for each server in parsed config, assertStringRecord(server.env, `${name}.env`)","typeGuard":"const isStringRecord = (v: unknown): v is Record<string, string> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v) &&\n  Object.values(v).every((x) => typeof x === 'string');","tryCatchPattern":null,"preventionTips":["Keep all env/headers values quoted in JSON, even booleans and numbers.","Add a JSON schema (additionalProperties: {type: 'string'}) and validate in editor/CI.","Run a preflight JSON parse + shape check before loadMcpConfig in scripts."],"tags":["config","validation","mcp","environment-variables"],"backgroundTag":"mcp-config-type-mismatch","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}