{"record":{"id":"3302b7cd6a178d26","repo":"gastownhall/beads","slug":"externaldoltconfig-tlscacert-q-is-not-absolute","errorCode":null,"errorMessage":"ExternalDoltConfig: TLSCACert %q is not absolute","messagePattern":"ExternalDoltConfig: TLSCACert %q is not absolute","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/external_dolt_config.go","lineNumber":77,"sourceCode":"\tif hasSocket && !filepath.IsAbs(c.Socket) {\n\t\treturn fmt.Errorf(\"ExternalDoltConfig: Socket %q is not absolute\", c.Socket)\n\t}\n\n\tswitch {\n\tcase c.TLSCert != \"\" && c.TLSKey == \"\":\n\t\treturn errors.New(\"ExternalDoltConfig: TLSCert set without TLSKey\")\n\tcase c.TLSCert == \"\" && c.TLSKey != \"\":\n\t\treturn errors.New(\"ExternalDoltConfig: TLSKey set without TLSCert\")\n\t}\n\n\tif c.TLSCert != \"\" && !filepath.IsAbs(c.TLSCert) {\n\t\treturn fmt.Errorf(\"ExternalDoltConfig: TLSCert %q is not absolute\", c.TLSCert)\n\t}\n\tif c.TLSKey != \"\" && !filepath.IsAbs(c.TLSKey) {\n\t\treturn fmt.Errorf(\"ExternalDoltConfig: TLSKey %q is not absolute\", c.TLSKey)\n\t}\n\tif c.TLSCACert != \"\" && !filepath.IsAbs(c.TLSCACert) {\n\t\treturn fmt.Errorf(\"ExternalDoltConfig: TLSCACert %q is not absolute\", c.TLSCACert)\n\t}\n\n\tif !c.TLSRequired {\n\t\tswitch {\n\t\tcase c.TLSCACert != \"\":\n\t\t\treturn errors.New(\"ExternalDoltConfig: TLSCACert set without TLSRequired\")\n\t\tcase c.TLSCert != \"\" || c.TLSKey != \"\":\n\t\t\treturn errors.New(\"ExternalDoltConfig: TLSCert/TLSKey set without TLSRequired\")\n\t\tcase c.TLSServerName != \"\":\n\t\t\treturn errors.New(\"ExternalDoltConfig: TLSServerName set without TLSRequired\")\n\t\tcase c.TLSSkipVerify:\n\t\t\treturn errors.New(\"ExternalDoltConfig: TLSSkipVerify set without TLSRequired\")\n\t\t}\n\t}\n\n\tif c.TLSRequired && hasSocket && c.TLSServerName == \"\" && !c.TLSSkipVerify {\n\t\treturn errors.New(\"ExternalDoltConfig: TLSRequired over Socket needs TLSServerName or TLSSkipVerify\")\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/external_dolt_config.go#L59-L95","documentation":"ExternalDoltConfig.Validate requires TLSCACert to be an absolute path when set. The CA bundle is read with os.ReadFile in TLSClientConfig to build the root cert pool; a relative path would depend on the working directory. Validation rejects it early, at config load/construction time.","triggerScenarios":"Calling Validate (via NewExternalDoltServer, NewExternalDoltServerUOWProvider, or buildProxiedServerClientInfo) with TLSCACert set to a relative path like \"ca.pem\" or \"~/ca.pem\" (tilde is not absolute to Go).","commonSituations":"Custom CA deployed to a nonstandard location referenced relatively; config templating that did not expand variables; moving configs between dev laptops and servers.","solutions":["Set TLSCACert to an absolute path, e.g. \"/etc/beads/tls/ca.pem\".","Expand \"~/\" or environment variables in the value before saving config.","If the server uses a CA already in the system pool, remove TLSCACert."],"exampleFix":"// before\ntlsCACert: \"./ca.pem\"\n// after\ntlsCACert: \"/usr/local/share/ca-certificates/dolt-ca.pem\"","handlingStrategy":"validation","validationCode":"func validTLSCACert(cfg configfile.ExternalDoltConfig) error {\n    if cfg.TLSCACert != \"\" && !filepath.IsAbs(cfg.TLSCACert) {\n        return fmt.Errorf(\"TLSCACert must be absolute: %q\", cfg.TLSCACert)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install custom CAs under a fixed absolute directory","Validate config at startup with a linter that checks path absoluteness","Rely on the system cert pool instead of TLSCACert when possible"],"tags":["config","validation","tls","path"],"backgroundTag":"invalid-config-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}