{"record":{"id":"26ac0772561937bf","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-hash-remote-management-key-w","errorCode":null,"errorMessage":"failed to hash remote management key: %w","messagePattern":"failed to hash remote management key: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config_load.go","lineNumber":107,"sourceCode":"\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 {\n\t\t\treturn nil, fmt.Errorf(\"failed to hash remote management key: %w\", errHash)\n\t\t}\n\t\tcfg.RemoteManagement.SecretKey = hashed\n\n\t\t// Persist the hashed value back to the config file to avoid re-hashing on next startup.\n\t\t// Preserve YAML comments and ordering; update only the nested key.\n\t\t_ = SaveConfigPreserveCommentsUpdateNestedScalar(configFile, []string{\"remote-management\", \"secret-key\"}, hashed)\n\t}\n\n\tcfg.RemoteManagement.PanelGitHubRepository = strings.TrimSpace(cfg.RemoteManagement.PanelGitHubRepository)\n\tif cfg.RemoteManagement.PanelGitHubRepository == \"\" {\n\t\tcfg.RemoteManagement.PanelGitHubRepository = DefaultPanelGitHubRepository\n\t}\n\n\tcfg.Pprof.Addr = strings.TrimSpace(cfg.Pprof.Addr)\n\tif cfg.Pprof.Addr == \"\" {\n\t\tcfg.Pprof.Addr = DefaultPprofAddr\n\t}\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/config_load.go#L89-L125","documentation":"If remote-management.secret-key is plaintext (not already a bcrypt hash), the loader hashes it with bcrypt and persists the hash back into the config. This error means bcrypt hashing itself failed — in practice, a secret longer than bcrypt's 72-byte input limit.","triggerScenarios":"cfg.RemoteManagement.SecretKey is non-empty, does not start with $2a$/$2b$/$2y$, and hashSecret (bcrypt.GenerateFromPassword) errors — classic cause: a generated API key/token over 72 bytes.","commonSituations":"Automation injects a long random token (e.g. 96+ char hex/base64) as the management key; pasting a full JWT instead of a short secret.","solutions":["Use a management secret of at most 72 bytes — a 32-byte random value (43-44 base64 chars) is plenty strong.","Or pre-hash the secret yourself once (htpasswd -bnBC 10 '' 'secret') and put the $2b$... string in the config so the loader skips re-hashing.","Regenerate the key rather than truncating silently if a long key was distributed."],"exampleFix":"# before (100+ char token, exceeds bcrypt limit)\nsecret-key: 4f8c...very-long-token...9a\n\n# after (32-byte base64url secret)\nsecret-key: qUx9m2P7vQ1sKd4LwN8zR3tY6bG5hJ0aXcV2eB4nM7o","handlingStrategy":"validation","validationCode":"const maxBcryptBytes = 72\nif len(cfg.RemoteManagement.SecretKey) > maxBcryptBytes && !looksLikeBcrypt(cfg.RemoteManagement.SecretKey) {\n\treturn fmt.Errorf(\"secret-key must be <= %d bytes or a pre-computed bcrypt hash\", maxBcryptBytes)\n}","typeGuard":"func isBcryptHash(s string) bool {\n\treturn strings.HasPrefix(s, \"$2a$\") || strings.HasPrefix(s, \"$2b$\") || strings.HasPrefix(s, \"$2y$\")\n}","tryCatchPattern":null,"preventionTips":["Keep management secrets under 72 bytes; 32 bytes of entropy is sufficient.","If you must inject long tokens, pre-hash them (htpasswd -bnBC 10) and store the $2b$ hash.","Note the loader rewrites config.yaml with the hash — do not fight it by re-deploying the plaintext each start."],"tags":["config","bcrypt","remote-management","secret-key","startup"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}