{"record":{"id":"efced1caf432a124","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-parse-config-file-w","errorCode":null,"errorMessage":"failed to parse config file: %w","messagePattern":"failed to parse config file: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/config/config_load.go","lineNumber":88,"sourceCode":"\tcfg.UsageStatisticsEnabled = false\n\tcfg.RedisUsageQueueRetentionSeconds = 60\n\tcfg.DisableCooling = false\n\tcfg.SaveCooldownStatus = false\n\tcfg.TransientErrorCooldownSeconds = 0\n\tcfg.DisableImageGeneration = DisableImageGenerationOff\n\tcfg.WebsocketAuth = true\n\tcfg.Pprof.Enable = false\n\tcfg.Pprof.Addr = DefaultPprofAddr\n\tcfg.RemoteManagement.PanelGitHubRepository = DefaultPanelGitHubRepository\n\tcfg.CredentialInFlight = DefaultCredentialInFlightConfig()\n\tif err = yaml.Unmarshal(data, &cfg); err != nil {\n\t\tif optional {\n\t\t\t// In cloud deploy mode, if YAML parsing fails, return empty config instead of error.\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, fmt.Errorf(\"failed to parse config file: %w\", err)\n\t}\n\n\tcfg.CredentialConcurrency = cfg.CredentialConcurrency.WithDefaults()\n\tif errValidate := cfg.CredentialInFlight.Validate(); errValidate != nil {\n\t\treturn nil, errValidate\n\t}\n\tif errValidate := cfg.Codex.LiveMediaRelay.Validate(); errValidate != nil {\n\t\treturn nil, errValidate\n\t}\n\tif errValidate := cfg.ValidateCredentialWeights(); errValidate != nil {\n\t\treturn nil, errValidate\n\t}\n\n\t// Hash remote management key if plaintext is detected (nested)\n\t// We consider a value to be already hashed if it looks like a bcrypt hash ($2a$, $2b$, or $2y$ prefix).\n\tif cfg.RemoteManagement.SecretKey != \"\" && !looksLikeBcrypt(cfg.RemoteManagement.SecretKey) {\n\t\thashed, errHash := hashSecret(cfg.RemoteManagement.SecretKey)\n\t\tif errHash != nil {","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/config_load.go#L70-L106","documentation":"The config file was read but gopkg.in/yaml.v3 could not unmarshal it into Config. In optional (cloud deploy) mode a parse failure silently yields an empty config; in normal mode it is fatal here. Typical causes are syntax errors: tabs used for indentation, unquoted special characters, duplicate keys, or truncated files.","triggerScenarios":"yaml.Unmarshal(data, &cfg) returns an error in non-optional mode — e.g. a tab character in indentation, an unquoted ':' inside a value, mismatched quotes, or the file was edited mid-deploy and is half-written.","commonSituations":"Hand-edited config introducing tabs; secrets with trailing colons or '#' unquoted; CI writing the file non-atomically; mixing JSON and YAML syntax.","solutions":["Paste the file into a YAML validator or run 'yamllint config.yaml' — the error offset from yaml.v3 points at the line.","Replace tabs with spaces, quote values containing ': ' or leading special chars.","If the file was truncated by a concurrent writer, restore from source control and write configs atomically (write temp + rename).","Beware optional mode: a silent empty config can mask this error — test parsing explicitly when deploying."],"exampleFix":"# before (tab indentation breaks YAML)\ncodex:\n\tlive-media-relay:\n\t\tenabled: true\n\n# after (spaces)\ncodex:\n  live-media-relay:\n    enabled: true","handlingStrategy":"validation","validationCode":"// Dry-parse the config before handing it to the server\nfunc configParses(path string) error {\n\tdata, err := os.ReadFile(path)\n\tif err != nil { return err }\n\tvar probe map[string]any\n\treturn yaml.Unmarshal(data, &probe)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run yamllint on config.yaml in CI and before manual edits.","Never use tabs for YAML indentation; quote values containing ':' or '#'.","Write config updates atomically (temp file + rename) to avoid truncated reads.","Remember optional mode silently swallows parse errors as an empty config — parse explicitly when that matters."],"tags":["config","yaml","parsing","startup"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}