{"record":{"id":"14ce28f72275aed9","repo":"gastownhall/beads","slug":"externaldoltconfig-tlscert-set-without-tlskey","errorCode":null,"errorMessage":"ExternalDoltConfig: TLSCert set without TLSKey","messagePattern":"ExternalDoltConfig: TLSCert set without TLSKey","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/external_dolt_config.go","lineNumber":65,"sourceCode":"\tcase !hasSocket && !hasHost && !hasPort:\n\t\treturn errors.New(\"ExternalDoltConfig: must set Socket or (Host, Port)\")\n\tcase hasHost && !hasPort:\n\t\treturn errors.New(\"ExternalDoltConfig: Host requires Port\")\n\tcase !hasHost && hasPort:\n\t\treturn errors.New(\"ExternalDoltConfig: Port requires Host\")\n\t}\n\n\tif hasHost && (c.Port < 1 || c.Port > 65535) {\n\t\treturn fmt.Errorf(\"ExternalDoltConfig: Port %d out of range [1, 65535]\", c.Port)\n\t}\n\n\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\")","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/external_dolt_config.go#L47-L83","documentation":"When request.WaitsFor is present, SpawnerID must be non-empty and Gate, if set, must be exactly \"all-children\" (types.WaitsForAllChildren) or \"any-children\" (types.WaitsForAnyChildren). Anything else is refused with this fixed message wrapped as ErrValidation.","triggerScenarios":"ExecuteCreate/ValidatePublicCreateRequest where WaitsFor.SpawnerID == \"\" or WaitsFor.Gate is a non-empty string other than the two allowed gate constants; check at public_create.go:187.","commonSituations":"Typo in the gate string (\"all_children\", \"any\", \"ALL\"), case mismatch, leaving SpawnerID unset while only setting Gate, or copying gate names from older API versions.","solutions":["Set SpawnerID to the spawner issue's ID and Gate to string(types.WaitsForAllChildren) or string(types.WaitsForAnyChildren).","Leave Gate empty to get the default (all-children is applied in PreparePublicCreateRequest).","Validate the gate against the constants rather than raw strings."],"exampleFix":"// before\nWaitsFor: &publicops.WaitsForInput{SpawnerID: \"mol-1\", Gate: \"all_children\"} // invalid gate\n// after\nWaitsFor: &publicops.WaitsForInput{SpawnerID: \"mol-1\", Gate: string(types.WaitsForAllChildren)}","handlingStrategy":"validation","validationCode":"if req.WaitsFor != nil {\n    if req.WaitsFor.SpawnerID == \"\" ||\n       (req.WaitsFor.Gate != \"\" && req.WaitsFor.Gate != string(types.WaitsForAllChildren) && req.WaitsFor.Gate != string(types.WaitsForAnyChildren)) {\n        return errors.New(\"waits-for spawner and gate are invalid\")\n    }\n}","typeGuard":"func waitsForValid(w *publicops.WaitsForInput) bool {\n    if w == nil { return true }\n    return w.SpawnerID != \"\" && (w.Gate == \"\" || w.Gate == string(types.WaitsForAllChildren) || w.Gate == string(types.WaitsForAnyChildren))\n}","tryCatchPattern":"if err := store.ExecuteCreate(ctx, req); err != nil {\n    if errors.Is(err, storage.ErrValidation) && strings.Contains(err.Error(), \"waits-for spawner and gate are invalid\") { /* fix gate/spawner */ }\n    return err\n}","preventionTips":["Use the types.WaitsForAllChildren / WaitsForAnyChildren constants, never literal strings.","Leave Gate empty to accept the default gate.","Always populate SpawnerID when setting WaitsFor."],"tags":["go","validation","waits-for","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}