hashicorp/nomad · error

Invalid node pool name '%s'

Error message

Invalid node pool name '%s'

What it means

Returned by acl.Parse in acl/policy.go:622 when a node_pool stanza's Name fails the validNodePool regex ^[a-zA-Z0-9-_*]{1,128}$ — allowed characters are letters, digits, hyphen, underscore, and asterisk, max 128 chars. Unlike namespaces, underscores ARE permitted for node pools, so the same name may be valid for one stanza type and invalid for the other.

Source

Thrown at acl/policy.go:622

				}
				for _, cap := range pathPolicy.Capabilities {
					if !isPathCapabilityValid(cap) {
						return nil, fmt.Errorf(
							"Invalid variable capability '%s' in namespace %s", cap, ns.Name)
					}
				}
				pathPolicy.Capabilities = expandVariablesCapabilities(pathPolicy.Capabilities)

			}
		}

		// Remove the namespace name from the extra key list.
		p.removeExtraKey(ns.Name)
	}

	for _, np := range p.NodePools {
		if !validNodePool.MatchString(np.Name) {
			return nil, fmt.Errorf("Invalid node pool name '%s'", np.Name)
		}
		if np.Policy != "" && !isPolicyValid(np.Policy) {
			return nil, fmt.Errorf("Invalid node pool policy '%s' for '%s'", np.Policy, np.Name)
		}
		for _, cap := range np.Capabilities {
			if !isNodePoolCapabilityValid(cap) {
				return nil, fmt.Errorf("Invalid node pool capability '%s' for '%s'", cap, np.Name)
			}
		}

		if np.Policy != "" {
			extraCap := expandNodePoolPolicy(np.Policy)
			np.Capabilities = append(np.Capabilities, extraCap...)
		}

		// Remove the node-pool name from the extra key list.
		p.removeExtraKey(np.Name)
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Rename the node pool to match ^[a-zA-Z0-9-_*]{1,128}$ (letters, digits, hyphen, underscore, asterisk)
  2. Remove leading/trailing whitespace and empty interpolations
  3. Shorten the name to <= 128 characters
  4. Pre-validate with the same regex in config CI before applying the policy

Example fix

// before
node_pool "prod.pool" {
  policy = "write"
}
// after
node_pool "prod-pool" {
  policy = "write"
}
Defensive patterns

Strategy: validation

Validate before calling

var validNodePool = regexp.MustCompile(`^[a-zA-Z0-9-_*]{1,128}$`)
for _, np := range policy.NodePools {
    if !validNodePool.MatchString(np.Name) {
        return fmt.Errorf("node pool %q does not match %s", np.Name, validNodePool)
    }
}

Type guard

func hasValidNodePoolName(name string) bool {
    return len(name) >= 1 && len(name) <= 128 &&
        strings.IndexFunc(name, func(r rune) bool {
            return !(r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' || r == '-' || r == '_' || r == '*')
        }) == -1
}

Prevention

When it happens

Trigger: Calling acl.Parse with node_pool { name = ... } containing illegal characters (spaces, dots, slashes), an empty name, or a name over 128 characters.

Common situations: Typos like "pool.1" or "team pool"; empty names from template interpolation; using the stricter namespace rules mentally and renaming pool names that contain dots; generated names with URL-encoded characters.

Related errors


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