thanos-io/thanos · error
node not in expected format
Error message
node not in expected format: %s
What it means
parseConfig in the memcache discovery resolver parses a cluster config payload whose nodes are space-separated `dns|ip|port` records. This error is returned when a node record does not split into exactly 3 pipe-delimited fields, meaning the endpoint string is malformed. It guards the resolver against partially-written or corrupted discovery configs.
Solutions
- Fix the config payload so every node is in `dns|ip|port` form with exactly two '|' separators, e.g. `memcached.local|10.0.0.1|11211`.
- Check for stray/extra whitespace or empty tokens between spaces in the nodes string and remove them.
- Regenerate the discovery config from the provider rather than editing it manually.
- Log the offending token (it is included in the error message) and correct that specific record.
Example fix
// before (payload nodes) "nodes": "mem1|10.0.0.1 mem2|10.0.0.2|11211" // after "nodes": "mem1|10.0.0.1|11211 mem2|10.0.0.2|11211"
Defensive patterns
Strategy: validation
Validate before calling
func validNodes(nodes string) bool {
for host := range strings.SplitSeq(strings.TrimSpace(nodes), " ") {
parts := strings.Split(host, "|")
if len(parts) != 3 {
return false
}
}
return true
} Prevention
- Generate memcache discovery configs with templates that enforce dns|ip|port per node.
- Trim and normalize whitespace in the nodes string before writing config.
- Add a config lint step in CI that validates the node format before deployment.
When it happens
Trigger: Calling Resolve (directly or in TestGoodClusterConfigs/TestBadClusterConfigs) with a config payload where any space-separated node token lacks two '|' separators, e.g. "host1|10.0.0.1 host2|10.0.0.2|11211" (first node missing the port field), or a token containing no '|' at all.
Common situations: Hand-edited memcache cluster config files, config templates where a trailing space creates an empty token, copy-paste losing pipe characters, or automation writing host:port instead of host|ip|port.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- failed to parse port
- failed to parse template
- failed to execute template
- failed to parse the template
- failed to execute the template
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/4bc2831361842396.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/discovery/memcache/resolver.go:101
}
clusterConfig.version, err = strconv.Atoi(strings.TrimSpace(configVersion))
if err != nil {
return nil, fmt.Errorf("failed to parser config version: %s", err)
}
nodes, err := reader.ReadString('\n')
if err != nil {
return nil, fmt.Errorf("failed to read nodes: %s", err)
}
if len(configVersion)+len(nodes) != configSize {
return nil, fmt.Errorf("expected %d in config payload, but got %d instead", configSize, len(configVersion)+len(nodes))
}
for host := range strings.SplitSeq(strings.TrimSpace(nodes), " ") {
dnsIpPort := strings.Split(host, "|")
if len(dnsIpPort) != 3 {
return nil, fmt.Errorf("node not in expected format: %s", dnsIpPort)
}
port, err := strconv.Atoi(dnsIpPort[2])
if err != nil {
return nil, fmt.Errorf("failed to parse port: %s, err: %s", dnsIpPort, err)
}
clusterConfig.nodes = append(clusterConfig.nodes, node{dns: dnsIpPort[0], ip: dnsIpPort[1], port: port})
}
return clusterConfig, nil
}
View on GitHub (pinned to 35b8b99117)