thanos-io/thanos · error

failed to parse port

Error message

failed to parse port: %s, err: %s

What it means

parseConfig validates each node record's third pipe-delimited field as the port and converts it with strconv.Atoi. This error is returned when that field is present (so the `dns|ip|port` shape is right) but is not a valid integer. It prevents a non-numeric port from entering the cluster config.

Solutions

  1. Correct the port field of the offending node record to a plain decimal integer (1-65535), e.g. `11211`.
  2. Check the full error message: the wrapped strconv error names the exact string that failed to parse.
  3. Validate the config with a script before deployment (split on space and '|', Atoi the third field).
  4. Ensure template substitution actually replaced port placeholders in the generated config.

Example fix

// before
"nodes": "mem1|10.0.0.1|http"
// after
"nodes": "mem1|10.0.0.1|11211"
Defensive patterns

Strategy: validation

Validate before calling

func validNodePorts(nodes string) error {
	for host := range strings.SplitSeq(strings.TrimSpace(nodes), " ") {
		parts := strings.Split(host, "|")
		if _, err := strconv.Atoi(parts[len(parts)-1]); err != nil {
			return fmt.Errorf("bad port in %q: %w", host, err)
		}
	}
	return nil
}

Prevention

When it happens

Trigger: Calling Resolve with a node token whose port field is non-numeric or empty-ish, e.g. "mem1|10.0.0.1|memcache" or "mem1|10.0.0.1|" style content that still yields 3 fields but where Atoi(dnsIpPort[2]) fails.

Common situations: Typos in config files (letters or symbols in the port field), placeholder text like `PORT` never substituted, or port fields pasted with surrounding whitespace that Atoi rejects.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/7425123018cfc2fc. Report an issue: GitHub.

Appendix: source

Thrown at pkg/discovery/memcache/resolver.go:105

	}

	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)