{"record":{"id":"abdd2c94103aa4be","repo":"affaan-m/ECC","slug":"name-references-undeclared-dependency-ref-0","errorCode":null,"errorMessage":"{name} references undeclared dependency: {ref[0]}","messagePattern":"(.+?) references undeclared dependency: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/workflow_graphs.py","lineNumber":100,"sourceCode":"            if dependency != 'input' and dependency not in nodes:\n                raise ValueError(f'Unknown dependency: {dependency}')\n    ancestors = {}\n\n    def visit(name, stack):\n        if name == 'input':\n            return set()\n        if name in stack:\n            raise ValueError('Dependency cycle')\n        if name not in ancestors:\n            deps = nodes[name].get('depends', [])\n            ancestors[name] = set(deps).union(*(visit(dep, stack | {name}) for dep in deps))\n        return ancestors[name]\n\n    for name, node in nodes.items():\n        reachable = visit(name, set())\n        for ref in references_in({'input': node.get('input'), 'fields': node.get('fields')}):\n            if ref[0] not in reachable:\n                raise ValueError(f'{name} references undeclared dependency: {ref[0]}')\n            if ref[0] == 'input':\n                if len(ref) < 2 or ref[1] not in inputs:\n                    raise ValueError('Unknown workflow input')\n                used.add(ref[1])\n    for ref in references_in(contents.get('output', {})):\n        if ref[0] not in nodes:\n            raise ValueError('Unknown output node')\n    if used != set(inputs):\n        raise ValueError(f'Unwired workflow inputs: {sorted(set(inputs) - used)}')\n\n\ndef load_graph(kind):\n    if kind not in ('apply', 'apply-motion', 'distill', 'prop3d'):\n        raise ValueError('Unknown workflow kind')\n    graph = json.loads((WORKFLOWS / f'taste-{kind}.json').read_text())\n    validate_graph(graph)\n    return graph\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/workflow_graphs.py#L82-L118","documentation":"validate_graph collects every field/input reference in a node (via references_in) and requires each referenced source to be inside the node's transitive depends set (reachable). If a reference names a node that is not a (transitive) dependency, the node would read data the graph never provides, so ValueError is raised.","triggerScenarios":"A node's input/fields entries reference e.g. ['distill','embedding'] while the node's depends array omits 'distill' (or omits an intermediate node through which it would be reachable).","commonSituations":"Adding a reference to another node's output but forgetting to add that node to depends; removing a depends entry while leaving the references; typos in node names in references.","solutions":["Add the referenced node's name to the consuming node's depends array in the workflow JSON","Check spelling of the reference against the exact node keys in nodes","If the reference is transitively available, verify each intermediate edge is present in depends chains","Remove the stale reference if the data is no longer needed"],"exampleFix":"// before\n{\"name\": \"apply\", \"depends\": [\"upscale\"], \"input\": \"{{distill.output}}\"}\n// after\n{\"name\": \"apply\", \"depends\": [\"upscale\", \"distill\"], \"input\": \"{{distill.output}}\"}","handlingStrategy":"validation","validationCode":"def deps_declared(node, nodes):\n    reachable = set()\n    stack = [node['name']]\n    while stack:\n        n = stack.pop()\n        for d in nodes[n].get('depends', []):\n            if d not in reachable:\n                reachable.add(d); stack.append(d)\n    refs = re.findall(r\"\\{\\{(\\w+)\\.\", json.dumps(node))\n    return all(r in reachable for r in refs)","typeGuard":null,"tryCatchPattern":"try:\n    graph = load_graph(kind)\nexcept ValueError as e:\n    if 'references undeclared dependency' in str(e):\n        node, ref = ...  # parse names from message\n        graph['nodes'][node]['depends'].append(ref)","preventionTips":["Add the depends entry in the same edit that adds a cross-node reference","Use a template/lint rule: every {{node.field}} reference must appear in depends","Review workflow diffs for asymmetric reference/depends changes"],"tags":["graph","configuration","dependency-validation"],"backgroundTag":"missing-dependency","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}