{"record":{"id":"cb2786ac7c0ee712","repo":"sipeed/picoclaw","slug":"failed-to-open-env-file-w","errorCode":null,"errorMessage":"failed to open env file: %w","messagePattern":"failed to open env file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/mcp/manager.go","lineNumber":71,"sourceCode":"\t\treq.Header.Set(key, value)\n\t}\n\n\t// Use the base transport\n\tbase := t.base\n\tif base == nil {\n\t\tbase = http.DefaultTransport\n\t}\n\treturn base.RoundTrip(req)\n}\n\n// loadEnvFile loads environment variables from a file in .env format\n// Each line should be in the format: KEY=value\n// Lines starting with # are comments\n// Empty lines are ignored\nfunc loadEnvFile(path string) (map[string]string, error) {\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open env file: %w\", err)\n\t}\n\tdefer file.Close()\n\n\tenvVars := make(map[string]string)\n\tscanner := bufio.NewScanner(file)\n\tlineNum := 0\n\n\tfor scanner.Scan() {\n\t\tlineNum++\n\t\tline := strings.TrimSpace(scanner.Text())\n\n\t\t// Skip empty lines and comments\n\t\tif line == \"\" || strings.HasPrefix(line, \"#\") {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse KEY=value\n\t\tparts := strings.SplitN(line, \"=\", 2)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/mcp/manager.go#L53-L89","documentation":"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.","triggerScenarios":"(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.","commonSituations":"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.","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"],"exampleFix":"# before\nmcp:\n  servers:\n    myserver:\n      env_file: .env      # resolved against process cwd\n\n# after\nmcp:\n  servers:\n    myserver:\n      env_file: /etc/picoclaw/myserver.env","handlingStrategy":"validation","validationCode":"for name, srv := range cfg.MCP.Servers {\n    if srv.EnvFile == \"\" {\n        continue\n    }\n    if _, err := os.Stat(srv.EnvFile); err != nil {\n        return fmt.Errorf(\"mcp server %s env_file %s unusable: %w\", name, srv.EnvFile, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := mcp.StartServers(cfg); err != nil {\n    if strings.Contains(err.Error(), \"failed to open env file\") {\n        // path is resolved against the process cwd — make env_file absolute and retry\n        return errors.New(\"env_file not found: use an absolute path in the MCP server config\")\n    }\n    return err\n}","preventionTips":["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"],"tags":["mcp","config","env-file","filesystem"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}