{"record":{"id":"a9ccee081a0f702f","repo":"projectdiscovery/nuclei","slug":"attribute-can-t-be-empty","errorCode":null,"errorMessage":"attribute can't be empty","messagePattern":"attribute can't be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/protocols/headless/engine/page_actions.go","lineNumber":838,"sourceCode":"\n\tif err = element.ScrollIntoView(); err != nil {\n\t\treturn errors.Wrap(err, errCouldNotScroll)\n\t}\n\n\ttarget, err := p.getActionArg(act, \"target\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswitch target {\n\tcase \"attribute\":\n\t\tattribute, err := p.getActionArg(act, \"attribute\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif attribute == \"\" {\n\t\t\treturn errors.New(\"attribute can't be empty\")\n\t\t}\n\n\t\tattrValue, err := element.Attribute(attribute)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"could not get attribute\")\n\t\t}\n\n\t\tif act.Name != \"\" {\n\t\t\tout[act.Name] = *attrValue\n\t\t}\n\tdefault:\n\t\ttext, err := element.Text()\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"could not get element text node\")\n\t\t}\n\n\t\tif act.Name != \"\" {\n\t\t\tout[act.Name] = text","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/protocols/headless/engine/page_actions.go#L820-L856","documentation":"In the extract/GetAttribute code path, when the extraction target is `attribute` the template must name which DOM attribute to read via the `attribute` arg. An empty value is rejected before element.Attribute is called, because reading an unnamed attribute is meaningless.","triggerScenarios":"A headless extract action like `action: extract ... by: attribute` (or getattribute) with the `attribute:` arg missing or set to an empty string in the step.","commonSituations":"Copying an extract-by-text example and changing only the `by` field; YAML indentation that places `attribute:` outside the step's args; template edits that delete the arg line.","solutions":["Add the attribute arg naming the DOM attribute to read (e.g. attribute: href, value, data-token)","Run `nuclei -t tpl.yaml -validate` to catch structurally valid but incomplete steps early","Check indentation so the arg lives inside the same action block"],"exampleFix":"# before\n- action: extract\n  by: attribute\n  name: token\n\n# after\n- action: extract\n  by: attribute\n  attribute: data-token\n  name: token","handlingStrategy":"validation","validationCode":"// when assembling steps programmatically\nif act.ActionType == engine.ActionExtract {\n    if strings.TrimSpace(act.GetArg(\"attribute\")) == \"\" && act.GetArg(\"by\") == \"attribute\" {\n        return errors.New(\"extract-by-attribute requires the attribute arg\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate templates with nuclei -validate after any edit","When using by: attribute, always pair it with attribute: <name> in the same step"],"tags":["headless","template","action-args","extract"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}