{"record":{"id":"5b46699f9d87ca62","repo":"AdguardTeam/AdGuardHome","slug":"invalid-value-q-empty-ipset-name","errorCode":null,"errorMessage":"invalid value %q: empty ipset name","messagePattern":"invalid value %q: empty ipset name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ipset/ipset_linux.go","lineNumber":248,"sourceCode":"// parseIpsetConfigLine parses one ipset configuration line.\nfunc parseIpsetConfigLine(confStr string) (hosts, ipsetNames []string, err error) {\n\tconfStr = strings.TrimSpace(confStr)\n\thostsAndNames := strings.Split(confStr, \"/\")\n\tif len(hostsAndNames) != 2 {\n\t\treturn nil, nil, fmt.Errorf(\"invalid value %q: expected one slash\", confStr)\n\t}\n\n\thosts = strings.Split(hostsAndNames[0], \",\")\n\tipsetNames = strings.Split(hostsAndNames[1], \",\")\n\n\tif len(ipsetNames) == 0 {\n\t\treturn nil, nil, nil\n\t}\n\n\tfor i := range ipsetNames {\n\t\tipsetNames[i] = strings.TrimSpace(ipsetNames[i])\n\t\tif len(ipsetNames[i]) == 0 {\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid value %q: empty ipset name\", confStr)\n\t\t}\n\t}\n\n\tfor i := range hosts {\n\t\thosts[i] = strings.ToLower(strings.TrimSpace(hosts[i]))\n\t}\n\n\treturn hosts, ipsetNames, nil\n}\n\n// parseIpsetConfig parses the ipset configuration and stores ipsets.  It\n// returns an error if the configuration can't be used.\nfunc (m *manager) parseIpsetConfig(ctx context.Context, ipsetConf []string) (err error) {\n\t// The family doesn't seem to matter when we use a header query, so query\n\t// only the IPv4 one.\n\t//\n\t// TODO(a.garipov): Find out if this is a bug or a feature.\n\tall, err := m.ipv4Conn.listAll()","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/ipset/ipset_linux.go#L230-L266","documentation":"The ipset-name side of a config line contained an empty element after trimming, e.g. 'host/' or 'host/a,,b'. Hosts may be empty but ipset names may not.","triggerScenarios":"parseIpsetConfigLine splits the right side on commas and finds an empty name: trailing slash, double comma, or whitespace-only name.","commonSituations":"Copy-paste config with a trailing comma, template-generated lines leaving an empty name, or a line of just '/' after trimming.","solutions":["Ensure every comma-separated ipset name is non-empty","Remove trailing commas/slashes from the line","Validate config lines in CI before deployment"],"exampleFix":"# before\n- example.org/\n# after\n- example.org/myset","handlingStrategy":"validation","validationCode":"func ipsetNamesNonEmpty(line string) bool {\n\tparts := strings.SplitN(line, \"/\", 2)\n\tif len(parts) != 2 { return false }\n\tfor _, n := range strings.Split(parts[1], \",\") {\n\t\tif strings.TrimSpace(n) == \"\" { return false }\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reject lines with trailing commas or slashes at config load time","Lint generated ipset config"],"tags":["ipset","config","validation"],"backgroundTag":"config-format-invalid","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}