hashicorp/nomad · error

root should be an object

Error message

root should be an object

What it means

After parsing the config, hclConfigToAny expects the top-level HCL node to be an ast.ObjectList (a block-style document). If the parsed root is something else (e.g. a bare expression/object), the structure is invalid and this error is returned.

Source

Thrown at plugins/shared/cmd/launcher/command/device.go:233

	return nil
}

func hclConfigToAny(config []byte) (any, error) {
	if len(config) == 0 {
		return map[string]any{}, nil
	}

	// Parse as we do in the jobspec parser
	root, err := hcl.Parse(string(config))
	if err != nil {
		return nil, fmt.Errorf("failed to hcl parse the config: %v", err)
	}

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

	var m map[string]any
	if err := hcl.DecodeObject(&m, list.Items[0]); err != nil {
		return nil, fmt.Errorf("failed to decode object: %v", err)
	}

	return m["config"], nil
}

func (c *Device) startRepl() error {
	// Start the output goroutine
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	fingerprint := make(chan context.Context)
	stats := make(chan context.Context)
	reserve := make(chan []string)
	go c.replOutput(ctx, fingerprint, stats, reserve)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Wrap the configuration in a proper top-level block, e.g. `config "mock" { ... }`.
  2. Convert JSON config to HCL block syntax used by the device plugin.
  3. Verify the launcher is reading the intended config file/section.

Example fix

// before
{ "foo": "bar" }
// after
config "mock" {
  foo = "bar"
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the config contains a top-level block before parsing
if !strings.Contains(string(config), "config ") {
	return errors.New("device config must define a top-level `config` block")
}

Try / catch

if err := setConfigErr; err != nil && err.Error() == "root should be an object" {
	// reject the config file and instruct the operator to use block syntax
}

Prevention

When it happens

Trigger: Passing config whose top level is not a block, e.g. a bare value like {"a":1}-style JSON or a scalar expression instead of `config "name" { ... }` blocks.

Common situations: Supplying JSON config where HCL blocks are expected (JSON objects parse to non-ObjectList nodes); config file containing only a key/value with no enclosing block; concatenating the wrong file.

Related errors


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