hashicorp/nomad · error

error parsing 'keyring': %w

Error message

error parsing 'keyring': %w

What it means

ParseConfigFile filters 'keyring' blocks and passes them to parseKeyringConfigs; this error wraps any failure there, such as a keyring provider block not decoding to a map or an extra key not decoding to a string.

Source

Thrown at command/agent/config_parse.go:103

		return nil, fmt.Errorf("error parsing: root should be an object")
	}
	matches := list.Filter("vault")
	if len(matches.Items) > 0 {
		if err := parseVaults(c, matches); err != nil {
			return nil, fmt.Errorf("error parsing 'vault': %w", err)
		}
	}
	matches = list.Filter("consul")
	if len(matches.Items) > 0 {
		if err := parseConsuls(c, matches); err != nil {
			return nil, fmt.Errorf("error parsing 'consul': %w", err)
		}
	}

	matches = list.Filter("keyring")
	if len(matches.Items) > 0 {
		if err := parseKeyringConfigs(c, matches); err != nil {
			return nil, fmt.Errorf("error parsing 'keyring': %w", err)
		}
	}

	// convert strings to time.Durations
	tds := []durationConversionMap{
		{"gc_interval", &c.Client.GCInterval, &c.Client.GCIntervalHCL, nil},
		{"acl.token_ttl", &c.ACL.TokenTTL, &c.ACL.TokenTTLHCL, nil},
		{"acl.policy_ttl", &c.ACL.PolicyTTL, &c.ACL.PolicyTTLHCL, nil},
		{"acl.policy_ttl", &c.ACL.RoleTTL, &c.ACL.RoleTTLHCL, nil},
		{"acl.token_min_expiration_ttl", &c.ACL.TokenMinExpirationTTL, &c.ACL.TokenMinExpirationTTLHCL, nil},
		{"acl.token_max_expiration_ttl", &c.ACL.TokenMaxExpirationTTL, &c.ACL.TokenMaxExpirationTTLHCL, nil},
		{"client.server_join.retry_interval", &c.Client.ServerJoin.RetryInterval, &c.Client.ServerJoin.RetryIntervalHCL, nil},
		{"server.heartbeat_grace", &c.Server.HeartbeatGrace, &c.Server.HeartbeatGraceHCL, nil},
		{"server.min_heartbeat_ttl", &c.Server.MinHeartbeatTTL, &c.Server.MinHeartbeatTTLHCL, nil},
		{"server.failover_heartbeat_ttl", &c.Server.FailoverHeartbeatTTL, &c.Server.FailoverHeartbeatTTLHCL, nil},
		{"server.plan_rejection_tracker.node_window", &c.Server.PlanRejectionTracker.NodeWindow, &c.Server.PlanRejectionTracker.NodeWindowHCL, nil},
		{"server.retry_interval", &c.Server.RetryInterval, &c.Server.RetryIntervalHCL, nil},
		{"server.server_join.retry_interval", &c.Server.ServerJoin.RetryInterval, &c.Server.ServerJoin.RetryIntervalHCL, nil},

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Quote extra key values in the keyring block so they decode as strings: `extra = "value"`
  2. Ensure each keyring provider block is an object/map, not a scalar or list
  3. Check the wrapped inner error in the message for the exact failing key
  4. Update the keyring stanza to match the schema expected by your vault/consul version

Example fix

// before
keyring {
  provider = "awskms"
  region = ["us-east-1"]
}

// after
keyring {
  provider = "awskms"
  region = "us-east-1"
}
Defensive patterns

Strategy: validation

Validate before calling

func validateKeyringTypes(data []byte) error {
	root, err := hcl.Parse(string(data))
	if err != nil {
		return err
	}
	list := root.Node.(*ast.ObjectList).Filter("keyring")
	for _, item := range list.Items {
		ot, ok := item.Val.(*ast.ObjectType)
		if !ok {
			return fmt.Errorf("keyring must be a braced block")
		}
		_ = ot // additionally assert each leaf value is a scalar string
	}
	return nil
}

Type guard

func keyringValIsString(m map[string]any, key string) bool {
	_, ok := m[key].(string)
	return ok
}

Try / catch

cfg, err := ParseConfigFile(path)
if err != nil {
	if strings.Contains(err.Error(), "error parsing 'keyring'") {
		return fmt.Errorf("invalid keyring stanza in %s: %w", path, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling ParseConfigFile/LoadConfig on a config with a `keyring { ... }` block that fails parseKeyringConfigs — e.g. provider block not an object/map, or an extra key listed in ExtraKeysHCL whose value is not a string.

Common situations: Keyring config with a non-string value like `extra = 42` or `extra = ["a"]` where a string is required; malformed keyring stanza copied between versions with different schema.

Related errors


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