{"record":{"id":"4bc2831361842396","repo":"thanos-io/thanos","slug":"node-not-in-expected-format-s","errorCode":null,"errorMessage":"node not in expected format: %s","messagePattern":"node not in expected format: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/discovery/memcache/resolver.go","lineNumber":101,"sourceCode":"\t}\n\tclusterConfig.version, err = strconv.Atoi(strings.TrimSpace(configVersion))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parser config version: %s\", err)\n\t}\n\n\tnodes, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read nodes: %s\", err)\n\t}\n\n\tif len(configVersion)+len(nodes) != configSize {\n\t\treturn nil, fmt.Errorf(\"expected %d in config payload, but got %d instead\", configSize, len(configVersion)+len(nodes))\n\t}\n\n\tfor host := range strings.SplitSeq(strings.TrimSpace(nodes), \" \") {\n\t\tdnsIpPort := strings.Split(host, \"|\")\n\t\tif len(dnsIpPort) != 3 {\n\t\t\treturn nil, fmt.Errorf(\"node not in expected format: %s\", dnsIpPort)\n\t\t}\n\t\tport, err := strconv.Atoi(dnsIpPort[2])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse port: %s, err: %s\", dnsIpPort, err)\n\t\t}\n\t\tclusterConfig.nodes = append(clusterConfig.nodes, node{dns: dnsIpPort[0], ip: dnsIpPort[1], port: port})\n\t}\n\n\treturn clusterConfig, nil\n}\n","sourceCodeStart":83,"sourceCodeEnd":112,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/discovery/memcache/resolver.go#L83-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (payload nodes)\n\"nodes\": \"mem1|10.0.0.1 mem2|10.0.0.2|11211\"\n// after\n\"nodes\": \"mem1|10.0.0.1|11211 mem2|10.0.0.2|11211\"","handlingStrategy":"validation","validationCode":"func validNodes(nodes string) bool {\n\tfor host := range strings.SplitSeq(strings.TrimSpace(nodes), \" \") {\n\t\tparts := strings.Split(host, \"|\")\n\t\tif len(parts) != 3 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["go","config-parsing","discovery","format-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}