{"record":{"id":"dbe6de6f687048b6","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-read-config-file-w","errorCode":null,"errorMessage":"failed to read config file: %w","messagePattern":"failed to read config file: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/config/config_load.go","lineNumber":44,"sourceCode":"\treturn LoadConfigOptional(configFile, false)\n}\n\n// LoadConfigOptional reads YAML from configFile.\n// If optional is true and the file is missing, it returns an empty Config.\n// If optional is true and the file is empty or invalid, it returns an empty Config.\nfunc LoadConfigOptional(configFile string, optional bool) (*Config, error) {\n\t// Read the entire configuration file into memory.\n\tdata, err := os.ReadFile(configFile)\n\tif err != nil {\n\t\tif optional {\n\t\t\tif os.IsNotExist(err) || errors.Is(err, syscall.EISDIR) {\n\t\t\t\t// Missing and optional: return empty config (cloud deploy standby).\n\t\t\t\tcfg := &Config{CredentialInFlight: DefaultCredentialInFlightConfig()}\n\t\t\t\tcfg.NormalizePluginsConfig()\n\t\t\t\treturn cfg, nil\n\t\t\t}\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to read config file: %w\", err)\n\t}\n\n\t// In cloud deploy mode (optional=true), if file is empty or contains only whitespace, return empty config.\n\tif optional && len(bytes.TrimSpace(data)) == 0 {\n\t\tcfg := &Config{CredentialInFlight: DefaultCredentialInFlightConfig()}\n\t\tcfg.NormalizePluginsConfig()\n\t\treturn cfg, nil\n\t}\n\n\tif errValidate := validateCredentialWeightYAML(data); errValidate != nil {\n\t\tif optional {\n\t\t\tcfgOptional := &Config{CredentialInFlight: DefaultCredentialInFlightConfig()}\n\t\t\tcfgOptional.NormalizePluginsConfig()\n\t\t\treturn cfgOptional, nil\n\t\t}\n\t\treturn nil, errValidate\n\t}\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/config_load.go#L26-L62","documentation":"Startup fails while reading the config file with os.ReadFile. In optional (cloud deploy) mode a missing file or directory is tolerated and returns an empty config; this error only escapes for other read failures — permission denied, path issues (a component of the path is not a directory), or the file being a directory in non-optional mode.","triggerScenarios":"LoadConfigOptional(configFile, optional=false) and os.ReadFile errors: EACCES (config not readable by the service user), ENOTDIR (path like /etc/config.yaml/x), EISDIR in non-optional mode, or I/O errors on the underlying disk.","commonSituations":"Running under systemd/container as a user without read permission on config.yaml; wrong --config path; file replaced by a directory by a provisioning script; NFS/mount hiccup.","solutions":["Check the file exists and is readable by the service user: ls -l <path> and sudo -u <user> cat <path>.","Fix the --config flag or CONFIG path to point at the real file.","If it is a directory or permission problem, correct ownership/mode (e.g. chmod 600 with the right owner).","The wrapped %w error names the exact syscall reason — read it first."],"exampleFix":"# before: unreadable config\n$ chmod 600 config.yaml   # owned by root, server runs as appuser\n\n# after\n$ chown appuser: config.yaml && chmod 600 config.yaml","handlingStrategy":"validation","validationCode":"// Pre-deploy check: file exists and is readable\ninfo, err := os.Stat(configPath)\nif err != nil { log.Fatal(\"config path invalid: \", err) }\nif info.IsDir() { log.Fatal(\"config path is a directory\") }\nif info.Mode().Perm()&0o400 == 0 { log.Fatal(\"config not readable\") }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify the service user can read the file before every deploy.","Pass an absolute path via --config to avoid cwd-dependent failures.","The wrapped error contains the exact syscall reason (EACCES/ENOTDIR/...) — always read it."],"tags":["config","filesystem","permissions","startup"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}