{"record":{"id":"589510eef9bdf439","repo":"sipeed/picoclaw","slug":"host-list-contains-an-empty-entry","errorCode":null,"errorMessage":"host list contains an empty entry","messagePattern":"host list contains an empty entry","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/netbind/netbind.go","lineNumber":454,"sourceCode":"\t\t}\n\t\tif _, ok := seen[token.key]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tseen[token.key] = struct{}{}\n\t\ttokens = append(tokens, token)\n\t}\n\n\tif len(tokens) == 0 {\n\t\treturn nil, errors.New(\"host cannot be empty\")\n\t}\n\n\treturn tokens, nil\n}\n\nfunc parseHostToken(raw string) (hostToken, error) {\n\thost := strings.TrimSpace(raw)\n\tif host == \"\" {\n\t\treturn hostToken{}, errors.New(\"host list contains an empty entry\")\n\t}\n\n\tif host == \"*\" {\n\t\treturn hostToken{kind: tokenStar, canonical: \"*\", key: \"*\"}, nil\n\t}\n\tif strings.EqualFold(host, \"localhost\") {\n\t\treturn hostToken{kind: tokenLocalhost, canonical: \"localhost\", key: \"localhost\"}, nil\n\t}\n\n\ttrimmed := strings.Trim(host, \"[]\")\n\tif ip := net.ParseIP(trimmed); ip != nil {\n\t\tif ip4 := ip.To4(); ip4 != nil {\n\t\t\tcanonical := ip4.String()\n\t\t\tkind := tokenIPv4\n\t\t\tif ip4.IsUnspecified() {\n\t\t\t\tkind = tokenIPv4Any\n\t\t\t}\n\t\t\treturn hostToken{kind: kind, canonical: canonical, key: canonical}, nil","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/netbind/netbind.go#L436-L472","documentation":"parseHostToken rejects an individual comma element that is empty after trimming. A host list may be empty overall (different error) but may not contain blank entries: \"localhost,,127.0.0.1\", \"a,b,\", \",a\" and \"a, ,b\" all fail here.","triggerScenarios":"Passing a comma-separated host spec with a leading/trailing comma, double commas, or whitespace-only entries between commas.","commonSituations":"Hosts list assembled by joining a slice containing empty strings; YAML flow sequence turned into a comma string with a trailing separator; copy-paste of \"127.0.0.1, \" from docs.","solutions":["Remove empty elements: keep only non-blank tokens before joining","Fix the literal: \"localhost,127.0.0.1\" instead of \"localhost,,127.0.0.1\"","Sanitize at the config layer: filter parts where strings.TrimSpace(part) != \"\""],"exampleFix":"// before\nhosts := strings.Join(cfg.Hosts, \",\") // cfg.Hosts contains \"\"\n\n// after\nvar clean []string\nfor _, h := range cfg.Hosts {\n    if strings.TrimSpace(h) != \"\" { clean = append(clean, h) }\n}\nhosts := strings.Join(clean, \",\")","handlingStrategy":"validation","validationCode":"func sanitizeHostList(raw string) (string, error) {\n    parts := strings.Split(raw, \",\")\n    keep := parts[:0]\n    for _, p := range parts {\n        if t := strings.TrimSpace(p); t != \"\" { keep = append(keep, t) }\n    }\n    if len(keep) == 0 { return \"\", errors.New(\"no hosts in list\") }\n    return strings.Join(keep, \",\"), nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter empty entries before joining host slices into a comma list","Avoid hand-writing comma lists; generate them from validated slices","Add a config lint that rejects ',,' , leading and trailing commas"],"tags":["netbind","networking","validation","configuration"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}