different-ai/openwork · error · ApiError
invalid_env_key
invalid_env_key
Error message
Invalid environment variable name
What it means
The GET /env/:key route validates the :key path parameter with isValidEnvKey() and rejects it with a 400 invalid_env_key ApiError when it is not a valid environment variable name. This guards against malformed or malicious keys before the env store is queried. It is purely client-input validation.
Source
Thrown at apps/server/src/routes/core.ts:419
addRoute(routes, "PUT", "/env/status", "host-token", async (ctx) => {
const body = await readJsonBody(ctx.request);
const runtimeKey = typeof body.runtimeKey === "string" && body.runtimeKey.trim()
? body.runtimeKey.trim()
: "default";
const pendingChanges = body.pendingChanges === true;
if (pendingChanges) {
envPendingChangesByRuntime.set(runtimeKey, true);
} else {
envPendingChangesByRuntime.delete(runtimeKey);
}
return jsonResponse({ runtimeKey, pendingChanges });
});
addRoute(routes, "GET", "/env/:key", "host-token", async (ctx) => {
const key = ctx.params.key;
if (!isValidEnvKey(key)) {
throw new ApiError(400, "invalid_env_key", "Invalid environment variable name");
}
const item = (await env.list().catch(rethrowEnvStoreReadError)).find((entry) => entry.key === key);
if (!item) {
throw new ApiError(404, "env_not_found", "Environment variable not found");
}
return jsonResponse({
item: {
key: item.key,
updatedAt: item.updatedAt,
hasValue: item.value.length > 0,
value: item.value,
},
});
});
addRoute(routes, "PUT", "/env", "host-token", async (ctx) => {
ensureWritable(config);
const body = await readJsonBody(ctx.request);View on GitHub (pinned to 2b7df46e8a)
Solutions
- Use a conventional env key: uppercase letters, digits, and underscores, not starting with a digit (e.g. MY_API_KEY)
- URL-encode the key with encodeURIComponent when building the request
- Trim whitespace and strip quotes from the key before sending
- Rename the variable on the producer side to a valid identifier
Example fix
// before
fetch(`/env/${key}`) // key = "my-var" -> 400
// after
const valid = /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
if (!valid) throw new Error(`invalid env key: ${key}`);
fetch(`/env/${encodeURIComponent(key)}`) Defensive patterns
Strategy: validation
Validate before calling
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
if (!ENV_KEY_RE.test(key)) throw new Error(`invalid env key: ${key}`); Type guard
function isValidEnvKeyName(key: string): boolean {
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
} Try / catch
try {
const res = await api.get(`/env/${encodeURIComponent(key)}`);
} catch (e) {
if (e.code === "invalid_env_key") throw new Error(`Key "${key}" is not a valid env name (use [A-Za-z_][A-Za-z0-9_]*)`);
throw e;
} Prevention
- Always encode the key with encodeURIComponent in URLs
- Normalize keys to SCREAMING_SNAKE_CASE before sending
- Reject dashes, spaces, and leading digits on input in your client
- Check the key against the same regex the server uses (isValidEnvKey) before calling
When it happens
Trigger: Calling GET /env/:key with a key containing characters outside the allowed set (e.g. spaces, '=', '-', unicode, empty string after decoding) or URL-encoding problems where the decoded key is invalid.
Common situations: A client builds the URL by string concatenation instead of encodeURIComponent; a key with lowercase/dashes convention from another system (e.g. 'my-var') is rejected; a script iterates keys from a file containing comments or blanks.
Related errors
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/2868894149c6c8aa.
Report an issue: GitHub.