{"record":{"id":"abb7b9e4c80405d0","repo":"nektos/act","slug":"unresolved-alias-node","errorCode":null,"errorMessage":"unresolved alias node","messagePattern":"unresolved alias node","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/anchors.go","lineNumber":17,"sourceCode":"package model\n\nimport (\n\t\"errors\"\n\n\t\"gopkg.in/yaml.v3\"\n)\n\nfunc resolveAliasesExt(node *yaml.Node, path map[*yaml.Node]bool, skipCheck bool) error {\n\tif !skipCheck && path[node] {\n\t\treturn errors.New(\"circular alias\")\n\t}\n\tswitch node.Kind {\n\tcase yaml.AliasNode:\n\t\taliasTarget := node.Alias\n\t\tif aliasTarget == nil {\n\t\t\treturn errors.New(\"unresolved alias node\")\n\t\t}\n\t\tpath[node] = true\n\t\t*node = *aliasTarget\n\t\tif err := resolveAliasesExt(node, path, true); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdelete(path, node)\n\n\tcase yaml.DocumentNode, yaml.MappingNode, yaml.SequenceNode:\n\t\tfor _, child := range node.Content {\n\t\t\tif err := resolveAliasesExt(child, path, false); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/model/anchors.go#L1-L35","documentation":"While inlining YAML aliases, resolveAliasesExt found an AliasNode whose .Alias pointer is nil — an alias node (*name) that does not point at any decoded anchor. Well-formed parsers never produce this, but truncated files, manual construction of yaml.Node trees, or pre-parsing that strips anchors can leave dangling alias nodes, which this guard rejects with 'unresolved alias node'.","triggerScenarios":"A workflow YAML containing '*foo' with no matching '&foo' anchor in the document; programmatically built or mutated yaml.Node trees where aliases were cloned without their targets; documents preprocessed by a tool that removed anchor definitions but kept the alias usages.","commonSituations":"Copy-pasting a snippet that uses an alias defined elsewhere in the original file; sed/script-based workflow refactors that delete the anchor line but not its references; partial merges of reusable workflow YAML; typos in alias names.","solutions":["Search the workflow for every '*name' usage and add the missing '&name:' anchor or fix the typo.","Replace the alias with a literal value if the anchor was intentionally removed.","If you preprocess YAML, run the alias check on the final merged document, not fragments.","Lint the file with any YAML validator to surface the undefined alias before running act."],"exampleFix":"# before\njobs:\n  build: &job_template\n    runs-on: ubuntu-latest\n  deploy: *job_templete   # typo -> unresolved alias node\n\n# after\njobs:\n  build: &job_template\n    runs-on: ubuntu-latest\n  deploy: *job_template","handlingStrategy":"validation","validationCode":"# Verify every alias has a matching anchor\npython3 - <<'EOF'\nimport re, sys\ntext = open(sys.argv[1]).read()\nanchors = set(re.findall(r'&(\\w+)', text))\naliases  = set(re.findall(r'\\*(\\w+)', text))\nmissing = aliases - anchors\nif missing:\n    sys.exit(f\"unresolved aliases: {sorted(missing)}\")\nprint(\"ok\")\nEOF","typeGuard":null,"tryCatchPattern":"if err := model.NewSingleWorkflowPlanner(path)(...) ; err != nil {\n    if strings.Contains(err.Error(), \"unresolved alias node\") {\n        return fmt.Errorf(\"an alias (*name) has no matching anchor (&name) in the workflow: %w\", err)\n    }\n    return err\n}","preventionTips":["After refactoring workflow YAML, grep aliases and anchors to confirm they pair up.","Never copy an '*alias' snippet without its '&' anchor definition.","Apply script-based YAML edits to the whole document, not fragments."],"tags":["yaml","aliases","workflow-parsing","configuration"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}