sipeed/picoclaw · error
failed to open env file: %w
Error message
failed to open env file: %w
What it means
loadEnvFile opens the env_file attached to an MCP server definition (KEY=value lines, # comments) with os.Open and wraps a failure here. The path is opened as given — relative paths resolve against the process working directory, not the config file location, which is the most common cause.
Source
Thrown at pkg/mcp/manager.go:71
req.Header.Set(key, value)
}
// Use the base transport
base := t.base
if base == nil {
base = http.DefaultTransport
}
return base.RoundTrip(req)
}
// loadEnvFile loads environment variables from a file in .env format
// Each line should be in the format: KEY=value
// Lines starting with # are comments
// Empty lines are ignored
func loadEnvFile(path string) (map[string]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open env file: %w", err)
}
defer file.Close()
envVars := make(map[string]string)
scanner := bufio.NewScanner(file)
lineNum := 0
for scanner.Scan() {
lineNum++
line := strings.TrimSpace(scanner.Text())
// Skip empty lines and comments
if line == "" || strings.HasPrefix(line, "#") {
continue
}
// Parse KEY=value
parts := strings.SplitN(line, "=", 2)View on GitHub (pinned to 49183d7e8d)
Solutions
- Use an absolute path for env_file in the MCP server config
- Create the file if missing (even empty) so Open succeeds
- chmod/chown so the running user can read it
- If the file is optional, remove the env_file key rather than pointing at a nonexistent path
Example fix
# before
mcp:
servers:
myserver:
env_file: .env # resolved against process cwd
# after
mcp:
servers:
myserver:
env_file: /etc/picoclaw/myserver.env Defensive patterns
Strategy: validation
Validate before calling
for name, srv := range cfg.MCP.Servers {
if srv.EnvFile == "" {
continue
}
if _, err := os.Stat(srv.EnvFile); err != nil {
return fmt.Errorf("mcp server %s env_file %s unusable: %w", name, srv.EnvFile, err)
}
} Try / catch
if err := mcp.StartServers(cfg); err != nil {
if strings.Contains(err.Error(), "failed to open env file") {
// path is resolved against the process cwd — make env_file absolute and retry
return errors.New("env_file not found: use an absolute path in the MCP server config")
}
return err
} Prevention
- Always use absolute env_file paths in MCP server definitions
- Create the file (even empty) at deploy time if the integration expects it to exist
- Check readability (os.Stat) for every env_file during config validation
When it happens
Trigger: (1) ENOENT: relative env_file like .env or ../secrets.env resolved from a different cwd (service started from another directory); file never created; typo in the path; (2) EACCES: file present but not readable by the process user.
Common situations: Starting the app from a different directory than during testing (relative .env worked interactively, fails as a daemon); env_file referenced in a shared MCP config that lacks the file on this machine; files created with restrictive umask or root ownership.
Related errors
- local command %q is a directory
- local command %q is not executable
- invalid format at line %d: %s
- ${label} must be a JSON object.
- ${label}.${key} must be a string.
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/cb2786ac7c0ee712.
Report an issue: GitHub.