hashicorp/nomad · error
invalid ';' character in CNI arg value %q
Error message
invalid ';' character in CNI arg value %q
What it means
Nomad rejects CNI arguments (cni_args) whose key or value contains a semicolon, because semicolons are the CNI_ARGS delimiter (key=value;key2=value2) and would allow argument injection/spoofing into the CNI plugin invocation. During group network validation, each arg is scanned with strings.Contains and appended to a multi-error.
Source
Thrown at nomad/structs/structs.go:7399
if net.CNI != nil {
for k, v := range net.CNI.Args {
if cniArgKeys.Contains(k) {
err := fmt.Errorf("duplicate CNI arg %q", k)
mErr.Errors = append(mErr.Errors, err)
} else {
cniArgKeys.Insert(k)
}
// CNI_ARGS is a ";"-separated string of "key=val", so a ";"
// in either key or val would confuse plugins (or libraries)
// that parse that string.
// Pre-validating this here protects job authors from submitting
// a job that will most likely error later on the client anyway.
if strings.Contains(k, ";") {
err := fmt.Errorf("invalid ';' character in CNI arg key %q", k)
mErr.Errors = append(mErr.Errors, err)
}
if strings.Contains(v, ";") {
err := fmt.Errorf("invalid ';' character in CNI arg value %q", v)
mErr.Errors = append(mErr.Errors, err)
}
}
}
// Validate the hostname field to be a valid DNS name. If the parameter
// looks like it includes an interpolation value, we skip this. It
// would be nice to validate additional parameters, but this isn't the
// right place.
if net.Hostname != "" && !strings.Contains(net.Hostname, "${") {
if _, ok := dns.IsDomainName(net.Hostname); !ok {
mErr.Errors = append(mErr.Errors, errors.New("Hostname is not a valid DNS name"))
}
}
}
// Check for duplicate tasks or port labels, and no duplicated static ports
for _, task := range tg.Tasks {View on GitHub (pinned to 482b49bf1a)
Solutions
- Remove the ';' from the CNI arg value, splitting into separate cni_args entries at the ';' delimiter.
- Encode the ';' (e.g. percent-escape or URL-encode) if the CNI plugin supports it and Nomad's version permits escaping.
- Validate the args locally with strings.Contains(v, ";") before submitting the job spec.
Example fix
// before
network { cni_args = ["K=V1;V2"] }
// after
network { cni_args = ["K=V1", "K2=V2"] } Defensive patterns
Strategy: validation
Validate before calling
for i, arg := range cniArgs {
kv := strings.SplitN(arg, "=", 2)
if len(kv) != 2 { return fmt.Errorf("cni_args[%d] not key=value", i) }
if strings.Contains(kv[0], ";") || strings.Contains(kv[1], ";") {
return fmt.Errorf("cni_args[%d] contains ';'", i)
}
} Prevention
- Keep cni_args entries as single key=value pairs without separators
- Escape or split any ';' before building the job spec
- Validate job specs with nomad job validate in CI
When it happens
Trigger: Defining a task group network block with cni_args where any key or value contains the ';' character, e.g. cni_args = ["FOO=bar;baz"], then submitting the job (job register/validate runs Validate).
Common situations: Copy-pasting CNI args from a Linux environment where semicolons are used as list separators; attempting to pass multiple CNI args in one string instead of separate list entries; template or env substitution injecting ';'.
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
- failed to initialize table forwarding rules: %v
- missing secret ID
- network namespace already exists but was misconfigured
- no CNI network config found
- namespace cannot contain template delimiters or parenthesis
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/2bf2fb7a0ba97f05.
Report an issue: GitHub.