{"record":{"id":"6b78ddf04c02e6c8","repo":"gastownhall/beads","slug":"externaldoltconfig-port-requires-host","errorCode":null,"errorMessage":"ExternalDoltConfig: Port requires Host","messagePattern":"ExternalDoltConfig: Port requires Host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/external_dolt_config.go","lineNumber":52,"sourceCode":"\t\treturn ExternalDoltConfigDefaultUser\n\t}\n\treturn c.User\n}\n\nfunc (c ExternalDoltConfig) Validate() error {\n\thasHost := c.Host != \"\"\n\thasPort := c.Port != 0\n\thasSocket := c.Socket != \"\"\n\n\tswitch {\n\tcase hasSocket && (hasHost || hasPort):\n\t\treturn errors.New(\"ExternalDoltConfig: set either Socket OR (Host, Port), not both\")\n\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) {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/external_dolt_config.go#L34-L70","documentation":"The waits-for specification's SpawnerID is length-checked via types.CheckFieldLen(\"waits-for spawner ID\", ...) and any over-length value is rejected wrapped as ErrValidation. Unlike other field-length failures, the message is just \"create: %w\" with no index because at most one WaitsFor is allowed per create.","triggerScenarios":"ExecuteCreate/ValidatePublicCreateRequest with request.WaitsFor != nil and WaitsFor.SpawnerID exceeding the allowed ID length; check at public_create.go:184.","commonSituations":"Passing a long external ref or URL as the spawner ID; duplicated prefix in a hand-built ID.","solutions":["Shorten the SpawnerID to the allowed length and use the canonical issue ID.","Pre-check with types.CheckFieldLen(\"waits-for spawner ID\", id) before building the request.","Verify the spawner issue exists too — length passes here but existence is checked at write time."],"exampleFix":"// before\nWaitsFor: &publicops.WaitsForInput{SpawnerID: \"mol-molecule-run-2026-08-30-long-identifier\"} // too long\n// after\nWaitsFor: &publicops.WaitsForInput{SpawnerID: \"mol-123\"}","handlingStrategy":"validation","validationCode":"if req.WaitsFor != nil {\n    if err := types.CheckFieldLen(\"waits-for spawner ID\", req.WaitsFor.SpawnerID); err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"if err := store.ExecuteCreate(ctx, req); err != nil {\n    if errors.Is(err, storage.ErrValidation) && errors.Is(err, types.ErrFieldTooLong) { /* shorten SpawnerID */ }\n    return err\n}","preventionTips":["Use the canonical short spawner issue ID.","Pre-check with types.CheckFieldLen before building the request.","Confirm the spawner exists in the same database."],"tags":["go","validation","field-length","waits-for"],"backgroundTag":"field-too-long","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}