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

  1. 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`.
  2. Check for stray/extra whitespace or empty tokens between spaces in the nodes string and remove them.
  3. Regenerate the discovery config from the provider rather than editing it manually.
  4. 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

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


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)