slopus/happy · warning
[EXPAND ENV] WARNING: ${varName} is set but EMPTY in daemon
Error message
[EXPAND ENV] WARNING: ${varName} is set but EMPTY in daemon environment What it means
expandEnvironmentVariables resolves ${VAR} references in profile environment using the daemon's environment. When a referenced variable IS present in the daemon env but resolves to the empty string, this warning is logged — usually a misconfiguration rather than a genuinely intended empty value.
Source
Thrown at packages/happy-cli/src/utils/expandEnvVars.ts:68
// Simple ${VAR} reference
varName = expr;
}
const resolvedValue = sourceEnv[varName];
if (resolvedValue !== undefined) {
// Variable found in source environment - use its value
// Log for debugging (mask secret-looking values)
const isSensitive = varName.toLowerCase().includes('token') ||
varName.toLowerCase().includes('key') ||
varName.toLowerCase().includes('secret');
const displayValue = isSensitive
? (resolvedValue ? `<${resolvedValue.length} chars>` : '<empty>')
: resolvedValue;
logger.debug(`[EXPAND ENV] Expanded ${varName} from daemon env: ${displayValue}`);
// Warn if empty string (common mistake)
if (resolvedValue === '') {
logger.warn(`[EXPAND ENV] WARNING: ${varName} is set but EMPTY in daemon environment`);
}
return resolvedValue;
} else if (defaultValue !== undefined) {
// Variable not found but default value provided - use default
logger.debug(`[EXPAND ENV] Using default value for ${varName}: ${defaultValue}`);
return defaultValue;
} else {
// Variable not found and no default - keep placeholder and warn
undefinedVars.push(varName);
return match;
}
});
expanded[key] = expandedValue;
}
// Log warning if any variables couldn't be resolvedView on GitHub (pinned to b824cd0a46)
Solutions
- Set the variable to a real value in the daemon's environment (systemd Environment=, docker -e, or the daemon's env file) and restart the daemon.
- If empty is legitimate, silence by using a default in the profile reference, e.g. ${VAR:-default}.
- Check the daemon env with `sudo systemctl show <daemon> -p Environment` or by dumping /proc/<pid>/environ.
- Remove the export VAR= line from shell profiles if it was accidental.
Example fix
// before (systemd unit) Environment=GEMINI_API_KEY= // after Environment=GEMINI_API_KEY=AIza...
Defensive patterns
Strategy: validation
Validate before calling
for (const v of ['MY_TOKEN', 'GEMINI_API_KEY']) {
if (process.env[v] === undefined) console.warn(`${v}: NOT SET in daemon env`);
else if (process.env[v] === '') console.warn(`${v}: set but EMPTY — fix daemon env file`);
} Prevention
- Never leave `VAR=` with an empty value in env files/systemd units.
- Use ${VAR:-default} references in profile env for optional values.
- After editing a daemon env, restart the daemon and re-check.
- Inspect actual daemon env via /proc/<pid>/environ when in doubt.
When it happens
Trigger: A profile env value like "TOKEN=${MY_TOKEN}" where MY_TOKEN exists in the daemon's process.env but equals "" (exported empty in systemd unit, docker ENV FOO=, or a shell profile exporting VAR=).
Common situations: Daemon (systemd/launchd/docker) environment defining the var as empty; user edited a dotenv/unit file and left the value blank; secrets manager injected an empty placeholder.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Daemon-spawned sessions cannot use local/interactive mode. U
- OpenClaw gateway not found. Either: - Install and run open
- Session environment is invalid - environment variables not f
- [EXPAND ENV] Undefined variables referenced in profile envir
- [EXPAND ENV] Session may fail to authenticate. Set these in
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/d6b4050dcb092f4d.
Report an issue: GitHub.