{"record":{"id":"c854a1f2bf80ba75","repo":"hasura/graphql-engine","slug":"error-reading-ca-s-w","errorCode":null,"errorMessage":"error reading CA %s: %w","messagePattern":"error reading CA (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/internal/httpc/httpc.go","lineNumber":198,"sourceCode":"}\n\nfunc GenerateTLSConfig(caPath string, insecureSkipTLSVerify bool) (*tls.Config, error) {\n\tvar op errors.Op = \"httpc.GenerateTLSConfig\"\n\n\ttlsConfig := &tls.Config{InsecureSkipVerify: insecureSkipTLSVerify}\n\n\tif caPath != \"\" {\n\t\t// Get the SystemCertPool, continue with an empty pool on error\n\t\trootCAs, _ := x509.SystemCertPool()\n\t\tif rootCAs == nil {\n\t\t\trootCAs = x509.NewCertPool()\n\t\t}\n\t\t// read cert\n\t\tcertPath, _ := filepath.Abs(caPath)\n\n\t\tcert, err := os.ReadFile(certPath)\n\t\tif err != nil {\n\t\t\treturn nil, errors.E(op, fmt.Errorf(\"error reading CA %s: %w\", caPath, err))\n\t\t}\n\n\t\tif ok := rootCAs.AppendCertsFromPEM(cert); !ok {\n\t\t\treturn nil, errors.E(op, stderrors.New(\"unable to append given CA cert\"))\n\t\t}\n\n\t\ttlsConfig.RootCAs = rootCAs\n\t}\n\n\treturn tlsConfig, nil\n}\n\nfunc NewHttpClientWithTLSConfig(tlsConfig *tls.Config) (*http.Client, error) {\n\ttr := &http.Transport{TLSClientConfig: tlsConfig}\n\ttr.Proxy = http.ProxyFromEnvironment\n\thttpClient := &http.Client{Transport: tr}\n\n\treturn httpClient, nil","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/internal/httpc/httpc.go#L180-L216","documentation":"Thrown by httpc.GenerateTLSConfig when the CA file configured for the client cannot be read from disk. The underlying os.ReadFile error is wrapped with the CA path, so the message shows both the configured path and the OS-level cause (no such file, permission denied, etc.).","triggerScenarios":"Setting a CA path in the CLI config (e.g. ca_cert in config.yaml or --ca-certificate flag) that does not exist, is a directory, has restrictive permissions, or is relative to a different working directory (it's resolved with filepath.Abs against the process CWD).","commonSituations":"Relative CA paths breaking when the CLI is run from another directory, wrong path after moving a project, expired cert files cleaned up, or file permissions blocking read access (common in CI containers running as a different user).","solutions":["Check the exact path in the error and verify the file exists at that absolute location","Use an absolute path for the CA cert, or run the CLI from the directory the relative path resolves from","Fix permissions: chmod 644 <ca.pem> and ensure the running user can read it","If the server uses a public CA, remove the CA config entirely"],"exampleFix":"# before\nca_cert: ./certs/ca.pem   # run from another dir -> ENOENT\n\n# after\nca_cert: /home/me/project/certs/ca.pem","handlingStrategy":"validation","validationCode":"if c.CAPath != \"\" {\n\tabs, err := filepath.Abs(c.CAPath)\n\tif err != nil { log.Fatal(err) }\n\tif fi, err := os.Stat(abs); err != nil || fi.IsDir() {\n\t\tlog.Fatalf(\"CA cert missing or unreadable: %s\", abs)\n\t}\n}","typeGuard":null,"tryCatchPattern":"cfg, err := httpc.GenerateTLSConfig(...)\nif err != nil {\n\tif strings.Contains(err.Error(), \"error reading CA\") {\n\t\t// fix the CA path in config before retrying; not retryable as-is\n\t}\n\treturn err\n}","preventionTips":["Use absolute CA cert paths in config files","Validate cert file existence at app startup","Ensure the running user (CI too) has read permission on the cert"],"tags":["tls","ca-certificate","file-io","config"],"backgroundTag":"ca-certificate-file-read-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}