{"record":{"id":"ee3f8384983017a5","repo":"hashicorp/nomad","slug":"failed-to-decode-object-v","errorCode":null,"errorMessage":"failed to decode object: %v","messagePattern":"failed to decode object: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/shared/cmd/launcher/command/device.go","lineNumber":238,"sourceCode":"\tif len(config) == 0 {\n\t\treturn map[string]any{}, nil\n\t}\n\n\t// Parse as we do in the jobspec parser\n\troot, err := hcl.Parse(string(config))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to hcl parse the config: %v\", err)\n\t}\n\n\t// Top-level item should be a list\n\tlist, ok := root.Node.(*ast.ObjectList)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"root should be an object\")\n\t}\n\n\tvar m map[string]any\n\tif err := hcl.DecodeObject(&m, list.Items[0]); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode object: %v\", err)\n\t}\n\n\treturn m[\"config\"], nil\n}\n\nfunc (c *Device) startRepl() error {\n\t// Start the output goroutine\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\tfingerprint := make(chan context.Context)\n\tstats := make(chan context.Context)\n\treserve := make(chan []string)\n\tgo c.replOutput(ctx, fingerprint, stats, reserve)\n\n\tc.Ui.Output(\"> Availabile commands are: exit(), fingerprint(), stop_fingerprint(), stats(), stop_stats(), reserve(id1, id2, ...)\")\n\tvar fingerprintCtx, statsCtx context.Context\n\tvar fingerprintCancel, statsCancel context.CancelFunc\n","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/plugins/shared/cmd/launcher/command/device.go#L220-L256","documentation":"Once the root is confirmed an ObjectList, the first item is decoded into a map via hcl.DecodeObject. Failure here (types not decodable, unsupported constructs) is wrapped as this error, before the function returns m[\"config\"].","triggerScenarios":"hcl.DecodeObject fails on the top-level block item, e.g. keys with incompatible value types, nested structures the legacy decoder cannot handle, or block items where assignments are expected.","commonSituations":"Config values with types the legacy hcl decoder mishandles (lists of objects, heredocs in odd positions); mixing blocks where a single object is expected; porting config from newer hcl2 syntax not supported by the legacy decoder.","solutions":["Simplify the top-level config block so its body decodes into a plain map (key = value assignments).","Move complex/nested structures under the `config` key with supported syntax.","Check the wrapped %v error for the offending key/line and fix its type.","Test the config through the device plugin's schema (hclspec) path if supported, which validates types earlier."],"exampleFix":"// before\nconfig \"mock\" {\n  options = [ { a = 1 } ]\n}\n// after\nconfig \"mock\" {\n  options = [\"a=1\"]\n}","handlingStrategy":"validation","validationCode":"// Prefer validating config against the device schema (hclspec) before legacy decode\nschema, err := c.getSpec()\nif err != nil {\n\treturn err\n}\nif _, diag := hclspecutils.Convert(schema); diag.HasErrors() {\n\treturn fmt.Errorf(\"device schema invalid: %v\", diag)\n}","typeGuard":null,"tryCatchPattern":"if err := setConfigErr; err != nil && strings.Contains(err.Error(), \"failed to decode object\") {\n\t// log the wrapped decoder error and fall back to schema-based parsing if available\n}","preventionTips":["Keep top-level config blocks to simple key = value assignments.","Avoid legacy-decoder-incompatible constructs (nested object lists) at the top level.","Validate configs against the device's hclspec schema during CI.","Pin configs to syntax supported by the legacy hcl package used by the launcher."],"tags":["hcl","config","decoding","device"],"backgroundTag":"hcl-parse-error","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}