{"record":{"id":"1d98dd887976cce3","repo":"gofr-dev/gofr","slug":"invalid-key-file","errorCode":null,"errorMessage":"invalid key file","messagePattern":"invalid key file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/gofr/http_server.go","lineNumber":33,"sourceCode":"\t\"gofr.dev/pkg/gofr/http/middleware\"\n\t\"gofr.dev/pkg/gofr/logging\"\n\t\"gofr.dev/pkg/gofr/websocket\"\n)\n\ntype httpServer struct {\n\trouter      *gofrHTTP.Router\n\tport        int\n\tws          *websocket.Manager\n\tsrvMu       sync.Mutex // guards srv, which run() writes on the serve goroutine and Shutdown() reads on the caller goroutine\n\tsrv         *http.Server\n\tcertFile    string\n\tkeyFile     string\n\tstaticFiles map[string]string\n}\n\nvar (\n\terrInvalidCertificateFile = errors.New(\"invalid certificate file\")\n\terrInvalidKeyFile         = errors.New(\"invalid key file\")\n)\n\n// logRouterChoice reports the route matcher the router resolved to.\n//\n// It stays quiet for the default, which every service gets and nobody needs told\n// about. It speaks up for the two cases that are worth a line: the opt-in matcher\n// being active, and a GOFR_ROUTER value that was not understood — the latter\n// falls back to mux, which looks exactly like never having set the variable, so a\n// typo would otherwise cost the opt-in with nothing said.\nfunc logRouterChoice(logger logging.Logger, r *gofrHTTP.Router) {\n\trequested := os.Getenv(gofrHTTP.RouterEnvVar)\n\tif requested == \"\" {\n\t\treturn\n\t}\n\n\tif !strings.EqualFold(requested, r.Matcher()) {\n\t\tlogger.Warnf(\"unrecognized %s value %q, using the %q router; valid values are %q and %q\",\n\t\t\tgofrHTTP.RouterEnvVar, requested, r.Matcher(), gofrHTTP.MatcherMux, gofrHTTP.MatcherTrie)","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/http_server.go#L15-L51","documentation":"errInvalidKeyFile is declared in pkg/gofr/http_server.go and returned by validateCertificateAndKeyFiles when the configured TLS private key file does not exist. Like the cert check, gofr validates the key file at startup so misconfigured TLS fails fast with a clear error.","triggerScenarios":"Starting the gofr server with a key-file path (HTTPS_KEY_FILE or config equivalent) where os.Stat returns IsNotExist; validateCertificateAndKeyFiles wraps the missing path with errInvalidKeyFile as '%w : %v'.","commonSituations":"Key stored separately from the cert (e.g. in a different K8s secret) and only the cert mounted; key regenerated with a new filename but config not updated; permissions preventing traversal is different, but a wrong path yields exactly this error.","solutions":["Confirm the key path exists from the process's working directory (ls -l <key path>)","Correct the HTTPS_KEY_FILE/config value to the real key location","Mount the key secret/volume into the container and re-deploy","Check you are not confusing the cert and key paths — they are validated in that order"],"exampleFix":"// before\nexport HTTPS_KEY_FILE=/etc/ssl/gofr/server.key  # not mounted\n// after\n# k8s: mount secret 'tls-key' at /etc/ssl/gofr/\nexport HTTPS_KEY_FILE=/etc/ssl/gofr/tls.key\nls -l /etc/ssl/gofr/tls.key","handlingStrategy":"validation","validationCode":"func checkKey(path string) error {\n    if path == \"\" {\n        return errors.New(\"key path not configured\")\n    }\n    if _, err := os.Stat(path); err != nil {\n        return fmt.Errorf(\"key file missing: %w\", err)\n    }\n    return nil\n}","typeGuard":"func isInvalidKey(err error) bool {\n    return errors.Is(err, errInvalidKeyFile)\n}","tryCatchPattern":"if err := server.Run(); err != nil {\n    if errors.Is(err, errInvalidKeyFile) {\n        log.Fatalf(\"TLS key missing: %v\", err)\n    }\n    return err\n}","preventionTips":["Deploy cert and key from the same secret/mount together","After cert renewal, update key paths in config in the same change","Stat both cert and key at container startup before binding the port","Keep key filenames stable across renewals or template them from config"],"tags":["tls","private-key","startup","configuration"],"backgroundTag":"missing-tls-key-file","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}