{"record":{"id":"40acbcd3c535132b","repo":"hashicorp/nomad","slug":"error-parsing-root-should-be-an-object-40acbc","errorCode":null,"errorMessage":"error parsing: root should be an object","messagePattern":"error parsing: root should be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"command/quota_apply.go","lineNumber":152,"sourceCode":"\t\tc.Ui.Error(fmt.Sprintf(\"Error applying quota specification: %s\", err))\n\t\treturn 1\n\t}\n\n\tc.Ui.Output(fmt.Sprintf(\"Successfully applied quota specification %q!\", spec.Name))\n\treturn 0\n}\n\n// parseQuotaSpec is used to parse the quota specification from HCL\nfunc parseQuotaSpec(input []byte) (*api.QuotaSpec, error) {\n\troot, err := hcl.ParseBytes(input)\n\tif err != nil {\n\t\treturn nil, 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(\"error parsing: root should be an object\")\n\t}\n\n\tvar spec api.QuotaSpec\n\tif err := parseQuotaSpecImpl(&spec, list); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &spec, nil\n}\n\n// parseQuotaSpecImpl parses the quota spec taking as input the AST tree\nfunc parseQuotaSpecImpl(result *api.QuotaSpec, list *ast.ObjectList) error {\n\t// Check for invalid keys\n\tvalid := []string{\n\t\t\"name\",\n\t\t\"description\",\n\t\t\"limit\",\n\t}","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/quota_apply.go#L134-L170","documentation":"`nomad quota apply -parse-only` (and related parsing) reads an HCL quota specification file and expects the top-level AST node to be an ObjectList (the file's body). If the parsed root is not an object (e.g. the file contains a bare scalar, list, or is otherwise malformed), parsing fails with this error.","triggerScenarios":"Passing a quota HCL file whose top level is not key/value blocks — e.g. an empty file, a file containing only a JSON array, or content that HCL parses into a non-object root.","commonSituations":"Uploading a JSON-encoded quota (which needs the .json extension/JSON parser) with a .hcl name, an accidentally emptied file, or a file with stray syntax that breaks HCL parsing.","solutions":["Ensure the quota file's top level is HCL object syntax: `name = \"...\"` plus `limits { ... }` blocks.","If the spec is JSON, keep the .json extension so the JSON parser is used.","Verify the file is non-empty and was not truncated or overwritten.","Check for characters before the first key (BOM, comments in wrong format) that can make the root parse as non-object."],"exampleFix":"// before (quota.hcl, invalid root)\n[\"team-a\"]\n\n// after\nname = \"team-a\"\ndescription = \"quota for team a\"\nlimits { region = \"global\" }","handlingStrategy":"validation","validationCode":"const content = fs.readFileSync(quotaFile, 'utf8');\nif (content.trim() === '') throw new Error('quota file is empty');\nif (quotaFile.endsWith('.json') && !content.trim().startsWith('{')) throw new Error('JSON quota must be an object at top level');\nif (!quotaFile.endsWith('.json') && !/^[a-zA-Z_]+\\s*=/.test(content.trim()) && !/(limits|name)\\s*[={]/.test(content)) throw new Error('HCL quota must start with key/value blocks');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep JSON quotas in .json files and HCL quotas in .nomad.hcl/.hcl files.","Run `nomad quota apply -parse-only` in CI before applying quota changes.","Never leave quota files empty; start with name = \"...\"."],"tags":["hcl","parsing","quota","nomad"],"backgroundTag":"hcl-parse-failed","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"}