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

  1. Rename keys to uppercase with underscores: MY-VAR → MY_VAR
  2. Ensure keys start with a letter or underscore
  3. 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

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


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/6872d2ce252ff380. Report an issue: GitHub.