hashicorp/nomad · error

error parsing topics: %w

Error message

error parsing topics: %w

What it means

EventStream parses the query string's topic parameters into a map of structs.Topic to key lists via parseEventTopics. Any failure from parseTopic for an individual topic= query parameter is wrapped with this message and returned to the stream request.

Source

Thrown at command/agent/event_endpoint.go:221

	codedErr := errs.Wait()
	if codedErr != nil && strings.Contains(codedErr.Error(), io.ErrClosedPipe.Error()) {
		codedErr = nil
	}

	return nil, codedErr
}

func parseEventTopics(query url.Values) (map[structs.Topic][]string, error) {
	raw, ok := query["topic"]
	if !ok {
		return allTopics(), nil
	}
	topics := make(map[structs.Topic][]string)

	for _, topic := range raw {
		k, v, err := parseTopic(topic)
		if err != nil {
			return nil, fmt.Errorf("error parsing topics: %w", err)
		}

		topics[structs.Topic(k)] = append(topics[structs.Topic(k)], v)
	}
	return topics, nil
}

func parseTopic(topic string) (string, string, error) {
	parts := strings.Split(topic, ":")
	// infer wildcard if only given a topic
	if len(parts) == 1 {
		return topic, "*", nil
	} else if len(parts) != 2 {
		return "", "", fmt.Errorf("Invalid key value pair for topic, topic: %s", topic)
	}
	return parts[0], parts[1], nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Use at most one colon per topic parameter: topic=NodeRegistration:node1 or topic=Deployment.
  2. Pass multiple topics as repeated parameters: topic=Evaluation:*&topic=Deployment:*.
  3. URL-encode any colon-bearing payload or split it into separate parameters.
  4. Use the wildcard topic=* to subscribe to everything and filter client-side.

Example fix

// before
GET /v1/event/stream?topic=Deployment:abc:def
// after
GET /v1/event/stream?topic=Deployment:*
Defensive patterns

Strategy: validation

Validate before calling

function buildTopicParam(key, value = '*') {
  if (/[\s]/.test(key) || (value && value.includes(':'))) {
    throw new Error(`invalid topic ${key}:${value}`)
  }
  return `topic=${encodeURIComponent(key)}:${encodeURIComponent(value)}`
}

Type guard

func validTopicParam(s string) bool {
  return strings.Count(s, ":") <= 1
}

Try / catch

topics, err := parseEventTopics(raw)
if err != nil {
  http.Error(w, "bad topic parameter; use topic=Name:value with at most one colon", 400)
  return
}

Prevention

When it happens

Trigger: GET /v1/event/stream with a topic= query parameter that parseTopic rejects — e.g. a value containing more than one colon such as topic=Deployment:abc:def.

Common situations: URL-encoded values containing colons (UUIDs are fine, but timestamps or joined key:value payloads are not); concatenating multiple key=value pairs into a single topic parameter.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/cd991b965d980fd8. Report an issue: GitHub.