{"record":{"id":"ec72b0ae14dfea4e","repo":"gastownhall/beads","slug":"externaldoltconfig-host-requires-port","errorCode":null,"errorMessage":"ExternalDoltConfig: Host requires Port","messagePattern":"ExternalDoltConfig: Host requires Port","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/external_dolt_config.go","lineNumber":50,"sourceCode":"func (c ExternalDoltConfig) ResolvedUser() string {\n\tif c.User == \"\" {\n\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}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/external_dolt_config.go#L32-L68","documentation":"A dependency's optional ThreadID is length-checked with types.CheckFieldLen(\"dependency thread_id\", ...); over-length values are rejected with the dependency's index in the message and wrapped as ErrValidation.","triggerScenarios":"ExecuteCreate/ValidatePublicCreateRequest where request.Dependencies[index].ThreadID exceeds the allowed field length; check at public_create.go:174.","commonSituations":"Storing long session/thread identifiers, concatenating thread metadata into the ID field, or a schema/config change that reduced the max length after existing data was written.","solutions":["Shorten the ThreadID to the allowed length.","Move auxiliary data into Metadata (valid JSON) instead of overloading ThreadID.","Pre-check with types.CheckFieldLen(\"dependency thread_id\", id) client-side."],"exampleFix":"// before\nThreadID: \"sess-2026-08-30T10:00:00Z-very-long-worker-uuid-0f3a9c...\" // too long\n// after\nThreadID: \"sess-0f3a9c\"","handlingStrategy":"validation","validationCode":"for i, d := range req.Dependencies {\n    if err := types.CheckFieldLen(\"dependency thread_id\", d.ThreadID); err != nil {\n        return fmt.Errorf(\"dependency %d: %w\", i, err)\n    }\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 ThreadID */ }\n    return err\n}","preventionTips":["Keep thread identifiers short and hash long values.","Move extra data into Metadata JSON.","Pre-check lengths with types.CheckFieldLen."],"tags":["go","validation","field-length","dependencies"],"backgroundTag":"field-too-long","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}