zeroclaw-labs/zeroclaw · error
{var_name} not found or empty in .env
Error message
{var_name} not found or empty in .env What it means
read_env_var resolves a variable strictly from the workspace .env file (not the process environment), parsing KEY=VALUE lines with optional export prefixes, comments, and quoted values. It bails when the key is absent or its parsed value is empty; this is how the image providers surface 'no API key configured'.
Source
Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:919
.with_context(|| format!("Failed to read {}", env_path.display()))?;
for line in content.lines() {
let line = line.trim();
if line.starts_with('#') || line.is_empty() {
continue;
}
let line = line.strip_prefix("export ").map(str::trim).unwrap_or(line);
if let Some((key, value)) = line.split_once('=')
&& key.trim() == var_name
{
let val = LinkedInClient::parse_env_value(value);
if !val.is_empty() {
return Ok(val);
}
}
}
anyhow::bail!("{var_name} not found or empty in .env")
}
fn http_client() -> reqwest::Client {
zeroclaw_config::schema::build_runtime_proxy_client_with_timeouts(
"tool.linkedin.image",
60, // image gen can be slow
10,
)
}
// ── Stability AI ────────────────────────────────────────────
async fn try_stability(
&self,
prompt: &str,
output_dir: &Path,
base_name: &str,
) -> anyhow::Result<PathBuf> {View on GitHub (pinned to 88bb9c8533)
Solutions
- Add an uncommented, non-empty KEY=value line to the .env inside the exact workspace_dir the client was constructed with
- Compare the variable name against the provider's api_key_env setting in config
- If you rely on process env vars, copy them into .env — this reader never consults the process environment
Example fix
# before # OPENAI_API_KEY=sk-... OPENAI_APIKEY=sk-... # after OPENAI_API_KEY=sk-...
Defensive patterns
Strategy: validation
Validate before calling
fn env_var_present(dir: &Path, key: &str) -> anyhow::Result<()> {
let content = std::fs::read_to_string(dir.join(".env")).context("workspace .env missing")?;
let ok = content.lines().any(|l| {
let l = l.trim().strip_prefix("export ").map(str::trim).unwrap_or(l.trim());
match l.split_once('=') {
Some((k, v)) => k.trim() == key && !v.trim().trim_matches('"').trim_matches('\'').is_empty(),
None => false,
}
});
anyhow::ensure!(ok, "{key} missing or empty in .env");
Ok(())
} Try / catch
Catch and report as configuration: name the missing variable (it is embedded in the message) and the workspace path searched — do not retry until the file is fixed.
Prevention
- Run a config check at startup that verifies every configured api_key_env resolves in the workspace .env
- Do not rely on process env vars — this reader only looks at the file
- Keep api_key_env names and .env keys in one place to avoid drift
When it happens
Trigger: The key is missing from .env; the line is commented out; the value is empty or only quotes; the workspace_dir contains no .env; or the provider's api_key_env setting names a different variable than the one stored in the file.
Common situations: Keys injected via docker/CI environment instead of the file; .env stored one directory above the workspace; spelling drift between the api_key_env config and the file.
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
- providers.models.ollama.{alias}.model uses ':cloud', but no
- GLM API key not set or invalid format. Expected 'id.secret'.
- API key prefix mismatch: key "{visible}..." looks like a {li
- LINKEDIN_ACCESS_TOKEN not found in .env for update
- email channel '{}' has oauth2 configured but no auth service
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/294938bee603b3b3.
Report an issue: GitHub.