hashicorp/nomad · error

namespace cannot contain template delimiters or parenthesis

Error message

namespace cannot contain template delimiters or parenthesis

What it means

The Nomad secrets template provider (nomad_provider.go) renders CT (Consul Template) snippets. validateNomadInputs rejects user-supplied namespaces that contain template delimiters '(' ')' '{' '}' so they cannot inject additional Consul Template functions or braces into the generated template. It returns 'namespace cannot contain template delimiters or parenthesis'.

Source

Thrown at client/allocrunner/taskrunner/secrets/nomad_provider.go:76

		{{ range $k, $v := . }}
		secret.%s.{{ $k }}={{ $v }}
		{{ end }}
		{{ end }}`,
		n.secret.Path, n.config.Namespace, n.secret.Name)

	return &structs.Template{
		EmbeddedTmpl: data,
		DestPath:     filepath.Clean(filepath.Join(n.secretDir, n.tmplFile)),
		ChangeMode:   structs.TemplateChangeModeNoop,
		Once:         true,
	}
}

// validateNomadInputs ensures none of the user provided inputs contain delimiters
// that could be used to inject other CT functions.
func validateNomadInputs(conf *nomadProviderConfig, path string) error {
	if strings.ContainsAny(conf.Namespace, "(){}") {
		return errors.New("namespace cannot contain template delimiters or parenthesis")
	}

	if strings.ContainsAny(path, "(){}") {
		return errors.New("path cannot contain template delimiters or parenthesis")
	}

	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove the ( ) { } characters from the namespace value in the secrets config
  2. URL-encode or otherwise escape the namespace at the source system (if the provider/API supports it) instead of embedding delimiters
  3. Use a namespace alias/name that is plain alphanumeric plus - _ . / only
  4. If the namespace legitimately needs these chars, upgrade Nomad or open an issue — validation is intentionally strict to block template injection

Example fix

// before
secret {
  config = { namespace = "prod(team-a)" }
}
// after
secret {
  config = { namespace = "prod-team-a" }
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: pre-validate the namespace before constructing the provider
func validNamespace(ns string) bool {
	return ns != "" && !strings.ContainsAny(ns, "(){}")
}
// usage
if !validNamespace(cfg.Namespace) {
	return errors.New("namespace must not contain ( ) { }")
}

Type guard

func isDelimiterFree(s string) bool { return !strings.ContainsAny(s, "(){}") }

Try / catch

p, err := NewNomadProvider(ctx, secret, dir)
if err != nil {
	if strings.Contains(err.Error(), "namespace cannot contain") {
		return nil, fmt.Errorf("fix secrets config: namespace rejected: %w", err)
	}
	return nil, err
}

Prevention

When it happens

Trigger: Creating a Nomad secrets provider via NewNomadProvider where conf.Namespace (from the secret stanza's config) contains any of the characters ( ) { } — e.g. namespace = "prod(1)" or a name with curly braces. The check is strings.ContainsAny(conf.Namespace, "(){}") and runs before the provider is constructed.

Common situations: Copy-pasting a namespace with stray whitespace/brackets, using templated or escaped namespace strings, or intentional-but-disallowed special characters in Vault/Nomad namespace names when wiring the secrets block into a task template.

Related errors


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