{"record":{"id":"a0135c19f6405055","repo":"gastownhall/beads","slug":"externaldoltconfig-read-tlscacert-w","errorCode":null,"errorMessage":"ExternalDoltConfig: read TLSCACert: %w","messagePattern":"ExternalDoltConfig: read TLSCACert: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/external_dolt_config.go","lineNumber":124,"sourceCode":"\t\treturn nil, nil\n\t}\n\n\tcfg := &tls.Config{MinVersion: tls.VersionTLS12}\n\n\tif c.TLSSkipVerify {\n\t\tcfg.InsecureSkipVerify = true //nolint:gosec // G402: opt-in insecure transport via the TLSSkipVerify testing flag\n\t} else {\n\t\tname := c.TLSServerName\n\t\tif name == \"\" {\n\t\t\tname = c.Host\n\t\t}\n\t\tcfg.ServerName = name\n\t}\n\n\tif c.TLSCACert != \"\" {\n\t\tpem, err := os.ReadFile(c.TLSCACert)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"ExternalDoltConfig: read TLSCACert: %w\", err)\n\t\t}\n\t\tpool := x509.NewCertPool()\n\t\tif !pool.AppendCertsFromPEM(pem) {\n\t\t\treturn nil, fmt.Errorf(\"ExternalDoltConfig: TLSCACert %q: no certificates parsed\", c.TLSCACert)\n\t\t}\n\t\tcfg.RootCAs = pool\n\t}\n\n\tif c.TLSCert != \"\" {\n\t\tcrt, err := tls.LoadX509KeyPair(c.TLSCert, c.TLSKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"ExternalDoltConfig: load client cert/key: %w\", err)\n\t\t}\n\t\tcfg.Certificates = []tls.Certificate{crt}\n\t}\n\n\treturn cfg, nil\n}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/external_dolt_config.go#L106-L142","documentation":"TLSClientConfig failed to read the TLSCACert file from disk and wraps the underlying os.ReadFile error. This happens after validation passed (path was absolute) but the file is missing, unreadable, or is a directory. The CA bundle is required to build the x509 root pool for verifying the external Dolt server.","triggerScenarios":"Calling registerExternalTLSConfig -> TLSClientConfig with TLSCACert pointing to a path that does not exist, has wrong permissions, or is a directory.","commonSituations":"Cert not deployed/provisioned on this machine; file deleted or rotated by cert management; path correct on another host; running as a user lacking read permission; SELinux/AppArmor blocking access.","solutions":["Verify the file exists at the exact TLSCACert path (ls -l) and fix the path if it was moved.","Fix permissions: chmod/chown so the running user can read the file, or run under an account with access.","Provision the CA file on this machine (copy it or re-run your cert deployment).","If the wrapped error is 'is a directory', point TLSCACert at the PEM file itself."],"exampleFix":"// before\ntlsCACert: \"/etc/beads/tls/ca.pem\"   // file missing\n// after\n# cp ca.pem /etc/beads/tls/ca.pem && chmod 644 /etc/beads/tls/ca.pem\ntlsCACert: \"/etc/beads/tls/ca.pem\"","handlingStrategy":"try-catch","validationCode":"if cfg.TLSCACert != \"\" {\n    if _, err := os.Stat(cfg.TLSCACert); err != nil {\n        return fmt.Errorf(\"CA cert not accessible: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"cfg, err := extCfg.TLSClientConfig()\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) {\n        log.Fatalf(\"CA cert unreadable at %s: %v — fix path/permissions\", perr.Path, perr.Err)\n    }\n    return err\n}","preventionTips":["Deploy CA files with a provisioning step and verify existence before starting the app","Run services under an account with read access to cert directories","Check the wrapped os error (EACCES vs ENOENT) to distinguish permissions from missing files"],"tags":["tls","filesystem","certificates","io"],"backgroundTag":"tls-ca-cert-unreadable","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}