affaan-m/ECC · error · ValueError

Node id mismatch

Error message

Node id mismatch: {name}

What it means

validate_graph checks that each entry key in contents['nodes'] matches that node's declared 'id' field. A mismatch means the graph JSON's node map key and internal id have drifted — references by name would resolve incorrectly, so load_graph refuses the graph with this ValueError.

Solutions

  1. Set the node's 'id' field to exactly match its key in the nodes dict (or vice versa)
  2. Re-generate the graph JSON from the canonical builder to restore key/id consistency
  3. Run a pre-check comparing each node key to node['id'] before load_graph

Example fix

// before
{"nodes": {"probe": {"id": "probe_v2", ...}}}
// after
{"nodes": {"probe": {"id": "probe", ...}}}
Defensive patterns

Strategy: validation

Validate before calling

def check_node_ids(graph):
    for name, node in graph['contents']['nodes'].items():
        if node['id'] != name:
            raise ValueError(f'Node id mismatch: {name}')

Type guard

def ids_consistent(graph) -> bool:
    nodes = graph['contents']['nodes']
    return all(node.get('id') == name for name, node in nodes.items())

Try / catch

try:
    graph = load_graph(path)
except ValueError as e:
    if 'Node id mismatch' in str(e):
        print(f'Graph JSON inconsistent, fix key/id: {e}')
    else:
        raise

Prevention

When it happens

Trigger: Loading a hand-edited or generated graph JSON where a node's 'id' field was changed (or its dict key renamed) so node['id'] != key, then calling load_graph.

Common situations: Renaming a node in one place (key or id) but not the other; a code generator emitting inconsistent ids; merge conflict leaving key/id divergent.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/325c23f5c6c2cdad. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/workflow_graphs.py:80

def references_in(value):
    if isinstance(value, str) and value.startswith('$'):
        yield value[1:].split('.')
    elif isinstance(value, dict):
        for child in value.values():
            yield from references_in(child)
    elif isinstance(value, list):
        for child in value:
            yield from references_in(child)


def validate_graph(graph):
    """Verify dependencies and every declared input; endpoint schemas need live QA."""
    contents = graph['contents']
    nodes, inputs = contents['nodes'], contents['schema']['input']
    used = set()
    for name, node in nodes.items():
        if node['id'] != name:
            raise ValueError(f'Node id mismatch: {name}')
        for dependency in node.get('depends', []):
            if dependency != 'input' and dependency not in nodes:
                raise ValueError(f'Unknown dependency: {dependency}')
    ancestors = {}

    def visit(name, stack):
        if name == 'input':
            return set()
        if name in stack:
            raise ValueError('Dependency cycle')
        if name not in ancestors:
            deps = nodes[name].get('depends', [])
            ancestors[name] = set(deps).union(*(visit(dep, stack | {name}) for dep in deps))
        return ancestors[name]

    for name, node in nodes.items():
        reachable = visit(name, set())
        for ref in references_in({'input': node.get('input'), 'fields': node.get('fields')}):

View on GitHub (pinned to 8321021c54)