hashicorp/nomad · error

error parsing: root should be an object

Error message

error parsing: root should be an object

What it means

parseVariableSpec parses HCL input for `var put` and expects the top-level node to be an ObjectList (an HCL object). If the parsed root is anything else (e.g. the file is JSON, or contains only scalar/list values), the parser returns the fixed message `error parsing: root should be an object`.

Source

Thrown at command/var_put.go:480

		out.CreateTime = 0
		out.ModifyIndex = 0
		out.ModifyTime = 0
	}
	return out, nil
}

// parseVariableSpec is used to parse the variable specification
// from HCL
func parseVariableSpec(input []byte, verbose func(string)) (*api.Variable, error) {
	root, err := hcl.ParseBytes(input)
	if err != nil {
		return nil, err
	}

	// Top-level item should be a list
	list, ok := root.Node.(*ast.ObjectList)
	if !ok {
		return nil, fmt.Errorf("error parsing: root should be an object")
	}

	var out api.Variable
	if err := parseVariableSpecImpl(&out, list); err != nil {
		return nil, err
	}
	return &out, nil
}

// parseVariableSpecImpl parses the variable taking as input the AST tree
func parseVariableSpecImpl(result *api.Variable, list *ast.ObjectList) error {
	// Decode the full thing into a map[string]interface for ease
	var m map[string]any
	if err := hcl.DecodeObject(&m, list); err != nil {
		return err
	}

	// Check for invalid keys

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the file actually contains HCL object syntax at top level (key = value or block {}), not JSON or a bare list.
  2. If the content is JSON, rerun with `-in=json`.
  3. Regenerate a valid template with `nomad var init` and port your values into it.
  4. Ensure the file is not empty or comment-only.

Example fix

// before (JSON passed as HCL)
{ "path": "app/config" }
// after (HCL form)
path = "app/config"
items { key = "value" }
Defensive patterns

Strategy: validation

Validate before calling

// pre-parse and confirm the HCL root is an object before invoking the command
f, _ := hcl.ParseBytes(data)
if _, ok := f.Node.(*hclast.ObjectList); !ok {
    return errors.New("HCL spec root must be an object (key = value / blocks)")
}

Type guard

func isHCLObjectRoot(data []byte) bool {
    root, err := hcl.ParseBytes(data)
    if err != nil { return false }
    _, ok := root.Node.(*hclast.ObjectList)
    return ok
}

Try / catch

if err := run(); err != nil && strings.Contains(err.Error(), "root should be an object") {
    log.Fatal("you likely passed JSON content with -in=hcl; switch flags or convert the file")
}

Prevention

When it happens

Trigger: Feeding `nomad var put -in=hcl` a file whose top level is not an HCL object — for example a bare JSON document (JSON object lists do not come through as *ast.ObjectList in this parser), a file containing only a list or a bare string, or an empty file.

Common situations: Mixing up -in flags: passing JSON content with -in=hcl; a spec file that starts with comments only; writing an HCL file with top-level array syntax `[...]` instead of blocks/assignments.

Related errors


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