hashicorp/nomad · error

[✘] Role data could not be deserialized: %w

Error message

[✘] Role data could not be deserialized: %w

What it means

In `nomad setup vault`, renderRole unmarshals the embedded vaultRoleBody JSON template into a map to build the Vault JWT auth role. If that compiled-in constant is not valid JSON, the unmarshal error is wrapped here. Like its Consul counterpart, the template ships with the binary, so failures indicate a corrupted or locally modified build.

Source

Thrown at command/setup_vault.go:433

    ttl = "1h"
  }
}`)
	return 0
}

func (s *SetupVaultCommand) roleExists() bool {
	existingRoles, _ := s.vLogical.List(fmt.Sprintf("/auth/%s/role", vaultPath))
	if existingRoles != nil {
		return slices.Contains(existingRoles.Data["keys"].([]any), vaultRole)
	}
	return false
}

func (s *SetupVaultCommand) renderRole() (map[string]any, error) {
	role := map[string]any{}
	err := json.Unmarshal(vaultRoleBody, &role)
	if err != nil {
		return role, fmt.Errorf("[✘] Role data could not be deserialized: %w", err)
	}

	role["bound_audiences"] = vaultAud

	return role, nil
}

func (s *SetupVaultCommand) createRole(role map[string]any) error {
	buf, err := json.Marshal(role)
	if err != nil {
		return fmt.Errorf("[✘] Role could not be interpolated with args: %w", err)
	}

	path := fmt.Sprintf("auth/%s/role/%s", vaultPath, vaultRole)

	_, err = s.vLogical.WriteBytes(path, buf)
	if err != nil {
		return fmt.Errorf("[✘] Could not create Vault role: %w", err)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Rebuild from a pristine checkout: `git checkout -- command/setup_vault.go && make build`, or reinstall the official release binary.
  2. Verify binary integrity against the official checksum for your Nomad version.
  3. If you customized vaultRoleBody, validate the JSON with `echo '<json>' | jq .` and fix syntax errors (trailing commas, unquoted keys, bad escapes).
  4. Work around by creating the Vault role manually: `vault write auth/nomad/role/nomad-workloads ...` with your own parameters instead of nomad setup.

Example fix

// before (broken embedded constant)
const vaultRoleBody = `{"user_claim": "https://nomad-project", "policies": ["nomad-workloads"],}`
// after (remove trailing comma)
const vaultRoleBody = `{"user_claim": "https://nomad-project", "policies": ["nomad-workloads"]}`
Defensive patterns

Strategy: type-guard

Validate before calling

// validate the embedded template before use
if !json.Valid([]byte(vaultRoleBody)) {
    return fmt.Errorf("vaultRoleBody is not valid JSON")
}

Type guard

func validJSONObject(b []byte) bool {
    var m map[string]any
    return json.Unmarshal(b, &m) == nil && m != nil
}

Try / catch

role := map[string]any{}
if err := json.Unmarshal(vaultRoleBody, &role); err != nil {
    return role, fmt.Errorf("[✘] Role data could not be deserialized: %w", err)
}

Prevention

When it happens

Trigger: json.Unmarshal(vaultRoleBody, &role) fails during `nomad setup vault` — the embedded role JSON is malformed, typically after source edits, a bad merge, or building from an incomplete checkout.

Common situations: Building Nomad from a fork where command/setup_vault.go's vaultRoleBody was edited with a JSON syntax error; merge conflict resolution leaving partial JSON; corrupted vendored/source tree; tooling that rewrites string constants breaking escaping.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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