{"record":{"id":"323e65022fdc9379","repo":"JuliusBrussee/caveman","slug":"invalid-listen-address-q-w","errorCode":null,"errorMessage":"invalid listen address %q: %w","messagePattern":"invalid listen address %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/runstate/runstate.go","lineNumber":55,"sourceCode":"type PublicState struct {\n\tOwner          string    `json:\"owner\"`\n\tMode           string    `json:\"mode,omitempty\"`\n\tInstanceToken  string    `json:\"instance_token,omitempty\"`\n\tPID            int       `json:\"pid,omitempty\"`\n\tPort           int       `json:\"port,omitempty\"`\n\tStartedAt      time.Time `json:\"started_at,omitempty\"`\n\tVersion        string    `json:\"version,omitempty\"`\n\tRecoveryViaMCP bool      `json:\"recovery_via_mcp\"`\n}\n\nfunc Unknown() PublicState {\n\treturn PublicState{Owner: \"unknown\"}\n}\n\nfunc PortFromListen(listen string) (int, error) {\n\t_, raw, err := net.SplitHostPort(listen)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"invalid listen address %q: %w\", listen, err)\n\t}\n\tport, err := strconv.Atoi(raw)\n\tif err != nil || port < 1 || port > 65535 {\n\t\treturn 0, fmt.Errorf(\"invalid listen port %q\", raw)\n\t}\n\treturn port, nil\n}\n\nfunc Path(home string, port int) string {\n\treturn filepath.Join(home, \"run\", strconv.Itoa(port)+\".json\")\n}\n\nfunc New(listen, mode, owner, version string) (State, error) {\n\tport, err := PortFromListen(listen)\n\tif err != nil {\n\t\treturn State{}, err\n\t}\n\tif owner != \"wrap\" && owner != \"start\" {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/internal/runstate/runstate.go#L37-L73","documentation":"Returned by runstate.PortFromListen when net.SplitHostPort cannot parse the listen string into host and port. The run-state file is keyed by port, so the listen address must be a plain host:port TCP address before a State can be built.","triggerScenarios":"Passing a listen value without a port (\"localhost\"), with an empty port (\"localhost:\"), with too many colons for a non-bracketed IPv6 literal (\"::1:8080\"), or with any other malformed host:port combination into runstate.New or PortFromListen.","commonSituations":"Configuring listen from a flag/env that accidentally holds a URL (\"http://localhost:8080\"), a Unix socket path, or an empty string; forgetting to bracket IPv6 addresses (should be \"[::1]:8080\"); trailing whitespace or quotes around the value in a YAML/env setting.","solutions":["Set listen to a bare host:port string such as \"127.0.0.1:8080\" or \":8080\"","Bracket IPv6 literals: \"[::1]:8080\"","Strip scheme/prefixes if the value comes from a URL — keep only host:port","Validate the flag at startup with net.SplitHostPort before passing it to runstate"],"exampleFix":"// before\nlisten := \"http://127.0.0.1:8080\"\nst, err := runstate.New(listen, \"record\", \"me\", \"1.0\")\n\n// after\nlisten := \"127.0.0.1:8080\"\nst, err := runstate.New(listen, \"record\", \"me\", \"1.0\")","handlingStrategy":"validation","validationCode":"func validListen(s string) error {\n    if _, port, err := net.SplitHostPort(s); err != nil {\n        return fmt.Errorf(\"listen %q must be host:port\", s)\n    } else if _, err := strconv.Atoi(port); err != nil {\n        return fmt.Errorf(\"listen port %q must be numeric\", port)\n    }\n    return nil\n}","typeGuard":"func isHostPort(s string) bool {\n    _, _, err := net.SplitHostPort(s)\n    return err == nil\n}","tryCatchPattern":"port, err := runstate.PortFromListen(listen)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid listen address\") {\n        return fmt.Errorf(\"config: fix listen to host:port (got %q)\", listen)\n    }\n}","preventionTips":["Source listen from a single validated config field, not free-form env text","Bracket IPv6 literals as [::]:8080","Add a startup config lint that runs SplitHostPort before any runstate call"],"tags":["config","network","validation","go"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}