nanocoai/nanoclaw · error · Error
env key ${JSON.stringify(key)} must be a valid environment v
Error message
env key ${JSON.stringify(key)} must be a valid environment variable name What it means
An env key in a stdio MCP entry fails the ENV_KEY_RE pattern for environment variable names (typically /^[A-Za-z_][A-Za-z0-9_]*$/). Keys with spaces, dashes, leading digits, or empty strings are rejected before they could break the container's env handling.
Source
Thrown at src/container-config.ts:187
const headers = parseStringRecord(input.headers, 'headers');
return {
type: 'http',
url,
...(headers === undefined ? {} : { headers }),
...(instructions === undefined ? {} : { instructions }),
};
}
if (command === undefined) throw new Error('Provide exactly one of command or url');
if (input.headers !== undefined) throw new Error('headers is only valid with url');
const args = input.args ?? [];
if (!Array.isArray(args) || !args.every((arg) => typeof arg === 'string')) {
throw new Error('args must be a JSON array of strings');
}
const env = parseStringRecord(input.env, 'env') ?? {};
for (const key of Object.keys(env)) {
if (!ENV_KEY_RE.test(key)) {
throw new Error(`env key ${JSON.stringify(key)} must be a valid environment variable name`);
}
}
const cwd = parseCwd(input.cwd);
return {
command,
args,
env,
...(cwd === undefined ? {} : { cwd }),
...(instructions === undefined ? {} : { instructions }),
};
}
function parseStringRecord(value: unknown, flag: string): Record<string, string> | undefined {
if (value === undefined) return undefined;
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
throw new Error(`${flag} must be a JSON object with string values`);
}
const record: Record<string, string> = {};View on GitHub (pinned to 294ef2aee8)
Solutions
- Rename keys to uppercase with underscores: MY-VAR → MY_VAR
- Ensure keys start with a letter or underscore
- Remove empty-string keys from the env object
Example fix
// before
{"env":{"my-var":"value"}}
// after
{"env":{"MY_VAR":"value"}} Defensive patterns
Strategy: validation
Validate before calling
for (const k of Object.keys(entry.env ?? {})) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new UserError(`bad env key: ${k}`); Type guard
const hasValidEnvKeys = (e: any) => Object.keys(e.env ?? {}).every(k => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k)); Try / catch
catch (err) { if (err.message.includes('valid environment variable name')) normalizeEnvKeys(); else throw err; } Prevention
- Uppercase + underscores for env keys
- Don't copy dash-style header names into env
When it happens
Trigger: env entries like {"MY-VAR":"x"}, {"1VAR":"x"}, {"my var":"x"}, or {"":"x"} in a stdio MCP server config.
Common situations: Copying header names (often dash-separated) into env; lowercase-with-dashes config style; templating artifacts producing empty keys.
Related errors
- type "stdio" requires command
- type "http" requires url
- MCP instructions must be a string
- Provide exactly one of command or url
- args, env, and cwd are only valid with command
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/6872d2ce252ff380.
Report an issue: GitHub.