{"record":{"id":"14c1471c4625525a","repo":"dotnet/runtime","slug":"expected-environment-variable-k-to-be-a-strin","errorCode":null,"errorMessage":"Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'","messagePattern":"Expected environment variable '(.+?)' to be a string but it was (.+?): '(.+?)'","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mono/browser/runtime/startup.ts","lineNumber":442,"sourceCode":"    const simd = loaderHelpers.simd();\n    const relaxedSimd = loaderHelpers.relaxedSimd();\n    const exceptions = loaderHelpers.exceptionsFinal();\n    runtimeHelpers.featureWasmSimd = await simd;\n    runtimeHelpers.featureWasmRelaxedSimd = await relaxedSimd;\n    runtimeHelpers.featureWasmFinalEh = await exceptions;\n}\n\nexport async function start_runtime () {\n    try {\n        const mark = startMeasure();\n        const environmentVariables = runtimeHelpers.config.environmentVariables || {};\n        mono_log_debug(\"Initializing mono runtime\");\n        for (const k in environmentVariables) {\n            const v = environmentVariables![k];\n            if (typeof (v) === \"string\")\n                mono_wasm_setenv(k, v);\n            else\n                throw new Error(`Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'`);\n        }\n        if (runtimeHelpers.config.runtimeOptions)\n            mono_wasm_set_runtime_options(runtimeHelpers.config.runtimeOptions);\n\n        if (runtimeHelpers.emscriptenBuildOptions.enableEventPipe) {\n            const diagnosticPorts = \"DOTNET_DiagnosticPorts\";\n            // connect JS client by default\n            const jsReady = \"js://ready\";\n            if (!environmentVariables[diagnosticPorts]) {\n                environmentVariables[diagnosticPorts] = jsReady;\n                mono_wasm_setenv(diagnosticPorts, jsReady);\n            }\n        } else if (runtimeHelpers.emscriptenBuildOptions.enableAotProfiler) {\n            mono_wasm_init_aot_profiler(runtimeHelpers.config.aotProfilerOptions || {});\n        } else if (runtimeHelpers.emscriptenBuildOptions.enableDevToolsProfiler) {\n            mono_wasm_init_devtools_profiler();\n        } else if (runtimeHelpers.emscriptenBuildOptions.enableLogProfiler) {\n            mono_wasm_init_log_profiler(runtimeHelpers.config.logProfilerOptions || {});","sourceCodeStart":424,"sourceCodeEnd":460,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/mono/browser/runtime/startup.ts#L424-L460","documentation":"Thrown by start_runtime while iterating config.environmentVariables: each value must be a string for mono_wasm_setenv, and any non-string value (number, boolean, object, null) is rejected with a message naming the offending key, its typeof, and value. This guards the environmentVariables dictionary before it is forwarded to native setenv.","triggerScenarios":"Providing runtimeHelpers.config.environmentVariables = { SOME_KEY: 123 } or { DEBUG: true } - any value that is not typeof 'string'. The check on line 439 fails and line 442 throws.","commonSituations":"Loading runtime config from JSON where numbers/booleans are not coerced to strings; passing a config object with structured values; environment-variable naming confusion where a value field holds an object.","solutions":["Ensure every value in environmentVariables is a string: coerce at config-build time, e.g. Object.fromEntries(Object.entries(env).map(([k,v]) => [k, String(v)])).","Validate the config object's environmentVariables field as Record<string,string> before start_runtime runs.","Fix the upstream source of the config (file, URL) to emit string values."],"exampleFix":"// before\nconfig.environmentVariables = { DOTNET_gcServer: 1 };\n// after\nconfig.environmentVariables = { DOTNET_gcServer: '1' };","handlingStrategy":"validation","validationCode":"function coerceEnvVars(env: Record<string, unknown>): Record<string, string> {\n  const out: Record<string, string> = {};\n  for (const [k, v] of Object.entries(env)) {\n    if (typeof v !== 'string') throw new Error(`environment variable '${k}' must be a string, got ${typeof v}`);\n    out[k] = v;\n  }\n  return out;\n}\nconfig.environmentVariables = coerceEnvVars(config.environmentVariables);","typeGuard":"function isStringRecord(o: unknown): o is Record<string, string> {\n  return !!o && typeof o === 'object' && Object.values(o).every(v => typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["Type environmentVariables as Record<string, string> in config schemas.","Coerce numbers/booleans to strings when loading config from JSON.","Validate the config object before start_runtime is invoked."],"tags":["startup","validation","environment-variables","config","typescript"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}