hashicorp/nomad · error
error parsing 'consul': %w
Error message
error parsing 'consul': %w
What it means
ParseConfigFile filters 'consul' blocks and passes them to parseConsuls; this error wraps any failure from that function. parseConsuls requires each consul block to be an object and decodes nested service_identity/template_identity blocks.
Source
Thrown at command/agent/config_parse.go:96
// need to parse by hand because we don't have a label on the block
root, err := hcl.Parse(buf.String())
if err != nil {
return nil, fmt.Errorf("failed to parse HCL file %s: %w", path, err)
}
list, ok := root.Node.(*ast.ObjectList)
if !ok {
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},View on GitHub (pinned to 482b49bf1a)
Solutions
- Write `consul` as a braced block: `consul { address = "127.0.0.1:8500" }`
- Verify nested service_identity/template_identity blocks are objects with valid syntax
- Run a syntax check / the agent with the config to get the wrapped underlying error message
- Restore the consul stanza from a known-good template
Example fix
// before
consul = "127.0.0.1:8500"
// after
consul {
address = "127.0.0.1:8500"
} Defensive patterns
Strategy: validation
Validate before calling
func validateConsulBlock(data []byte) error {
root, err := hcl.Parse(string(data))
if err != nil {
return err
}
list, ok := root.Node.(*ast.ObjectList)
if !ok {
return fmt.Errorf("root is not an object")
}
for _, item := range list.Filter("consul").Items {
if _, ok := item.Val.(*ast.ObjectType); !ok {
return fmt.Errorf("consul must be a braced block")
}
}
return nil
} Type guard
func isConsulBlock(obj *ast.ObjectItem) bool {
_, ok := obj.Val.(*ast.ObjectType)
return ok
} Try / catch
cfg, err := ParseConfigFile(path)
if err != nil {
if strings.Contains(err.Error(), "error parsing 'consul'") {
return fmt.Errorf("invalid consul stanza in %s: %w", path, err)
}
return err
} Prevention
- Write consul as a braced block with key = value lines inside
- Check nested service_identity/template_identity blocks are objects
- Validate configs in CI before rollout
- Restore stanzas from templates rather than free-hand edits
When it happens
Trigger: Calling ParseConfigFile/LoadConfig on a config with a `consul { ... }` block whose value is not an object type (e.g. `consul = 5`), or whose nested service_identity/template_identity blocks fail hcl.DecodeObject.
Common situations: Typo turning a consul block into an assignment; YAML-to-HCL conversion producing wrong syntax; editing consul stanza by hand and dropping braces.
Related errors
- Invalid quota policy: %#v
- Invalid plugin policy: %#v
- invalid acl policy: %v
- failed to parse policy: %w
- Error loading %s: %s
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/23589f2ecfd0e9a9.
Report an issue: GitHub.