hashicorp/nomad · error

failed to decode HCL file %s: %w

Error message

failed to decode HCL file %s: %w

What it means

ParseConfigFile reads the config file and decodes it into a Config struct via hcl.Decode. If HCL decoding fails (valid text but structure/types don't match the Config schema), the error is wrapped as 'failed to decode HCL file <path>'.

Source

Thrown at command/agent/config_parse.go:74

		},
		Server: &ServerConfig{
			ClientIntroduction:   &ClientIntroduction{},
			PlanRejectionTracker: &PlanRejectionTracker{},
			ServerJoin:           &ServerJoin{},
		},
		ACL:       &ACLConfig{},
		RPC:       &RPCConfig{},
		Audit:     &config.AuditConfig{},
		Consuls:   []*config.ConsulConfig{},
		Autopilot: &config.AutopilotConfig{},
		Telemetry: &Telemetry{},
		Vaults:    []*config.VaultConfig{},
		Reporting: config.DefaultReporting(),
	}

	err = hcl.Decode(c, buf.String())
	if err != nil {
		return nil, fmt.Errorf("failed to decode HCL file %s: %w", path, err)
	}

	// Re-parse the file to extract the multiple Vault configurations, which we
	// 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)
		}
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped %w error — it pinpoints the field/type that failed to decode
  2. Fix the value type to match the expected schema (e.g. numbers for ports, lists for bind addresses arrays)
  3. Check docs for your Consul version — schema differs across versions
  4. Run the file through hclfmt and compare with a known-good example config

Example fix

// before
ports { http = "8500" }  // wrong type
// after
ports { http = 8500 }
Defensive patterns

Strategy: validation

Validate before calling

src, err := os.ReadFile(path)
if err != nil { return err }
var probe map[string]interface{}
if err := hcl.Decode(&probe, string(src)); err != nil {
    return fmt.Errorf("HCL decode pre-check failed: %w", err)
}

Try / catch

cfg, err := agentcfg.ParseConfigFile(path)
if err != nil {
    var derr *hcl.Error
    if errors.As(err, &derr) {
        return fmt.Errorf("fix types/keys near %v", derr)
    }
    return err
}

Prevention

When it happens

Trigger: A config file whose syntax parses but whose keys/types don't fit the Config struct — e.g. a value where a list is expected, unknown nested blocks, or type mismatches (string vs number) that hcl.Decode rejects.

Common situations: Wrong value types (ports as strings vs numbers depending on version), copy-pasted blocks from newer Consul versions into older ones, typos in block/keys causing mapping failures.

Understand the failure class

Related errors


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