dotnet/runtime · error · Error
Expected environment variable '${k}' to be a string but it w
Error message
Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}' What it means
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.
Source
Thrown at src/mono/browser/runtime/startup.ts:442
const simd = loaderHelpers.simd();
const relaxedSimd = loaderHelpers.relaxedSimd();
const exceptions = loaderHelpers.exceptionsFinal();
runtimeHelpers.featureWasmSimd = await simd;
runtimeHelpers.featureWasmRelaxedSimd = await relaxedSimd;
runtimeHelpers.featureWasmFinalEh = await exceptions;
}
export async function start_runtime () {
try {
const mark = startMeasure();
const environmentVariables = runtimeHelpers.config.environmentVariables || {};
mono_log_debug("Initializing mono runtime");
for (const k in environmentVariables) {
const v = environmentVariables![k];
if (typeof (v) === "string")
mono_wasm_setenv(k, v);
else
throw new Error(`Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'`);
}
if (runtimeHelpers.config.runtimeOptions)
mono_wasm_set_runtime_options(runtimeHelpers.config.runtimeOptions);
if (runtimeHelpers.emscriptenBuildOptions.enableEventPipe) {
const diagnosticPorts = "DOTNET_DiagnosticPorts";
// connect JS client by default
const jsReady = "js://ready";
if (!environmentVariables[diagnosticPorts]) {
environmentVariables[diagnosticPorts] = jsReady;
mono_wasm_setenv(diagnosticPorts, jsReady);
}
} else if (runtimeHelpers.emscriptenBuildOptions.enableAotProfiler) {
mono_wasm_init_aot_profiler(runtimeHelpers.config.aotProfilerOptions || {});
} else if (runtimeHelpers.emscriptenBuildOptions.enableDevToolsProfiler) {
mono_wasm_init_devtools_profiler();
} else if (runtimeHelpers.emscriptenBuildOptions.enableLogProfiler) {
mono_wasm_init_log_profiler(runtimeHelpers.config.logProfilerOptions || {});View on GitHub (pinned to 60108ba66e)
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.
Example fix
// before
config.environmentVariables = { DOTNET_gcServer: 1 };
// after
config.environmentVariables = { DOTNET_gcServer: '1' }; Defensive patterns
Strategy: validation
Validate before calling
function coerceEnvVars(env: Record<string, unknown>): Record<string, string> {
const out: Record<string, string> = {};
for (const [k, v] of Object.entries(env)) {
if (typeof v !== 'string') throw new Error(`environment variable '${k}' must be a string, got ${typeof v}`);
out[k] = v;
}
return out;
}
config.environmentVariables = coerceEnvVars(config.environmentVariables); Type guard
function isStringRecord(o: unknown): o is Record<string, string> {
return !!o && typeof o === 'object' && Object.values(o).every(v => typeof v === 'string');
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Expected runtimeOptions to be an array of strings
- event must be an object, but got ${JSON.stringify(event)}
- event.eventName is a required parameter, in event: ${JSON.st
- args must be an object, but got ${JSON.stringify(args)}
- "arguments" should be an array, but was ${request.arguments}
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/14c1471c4625525a.
Report an issue: GitHub.