{"record":{"id":"69523cb6f547d574","repo":"oracle/graal","slug":"edge","errorCode":null,"errorMessage":"Edge ","messagePattern":"Edge ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graphio/GraphProtocol.java","lineNumber":567,"sourceCode":"            writeEdges(info, node, false);\n\n            props.clear();\n            cnt++;\n        }\n        if (size != cnt) {\n            throw new IOException(\"Expecting \" + size + \" nodes, but found \" + cnt);\n        }\n    }\n\n    private void writeEdges(Graph graph, Node node, boolean dumpInputs) throws IOException {\n        NodeClass clazz = classForNode(node);\n        Edges edges = findClassEdges(clazz, dumpInputs);\n        int size = findSize(edges);\n        for (int i = 0; i < size; i++) {\n            Collection<? extends Node> list = findNodes(graph, node, edges, i);\n            if (isDirect(edges, i)) {\n                if (list != null && list.size() != 1) {\n                    throw new IOException(\"Edge \" + i + \" in \" + edges + \" is direct, but list isn't singleton: \" + list);\n                }\n                Node n = null;\n                if (list != null && !list.isEmpty()) {\n                    n = list.iterator().next();\n                }\n                writeNodeRef(n);\n            } else {\n                if (list == null) {\n                    writeShort((char) 0);\n                } else {\n                    int listSize = list.size();\n                    if (listSize != ((char) listSize)) {\n                        throw new IOException(\"Too many nodes in list: \" + list.size());\n                    }\n                    writeShort((char) listSize);\n                    for (Node edge : list) {\n                        writeNodeRef(edge);\n                    }","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graphio/GraphProtocol.java#L549-L585","documentation":"In the dump protocol, an edge declared 'direct' (a single @Input/@Successor, not a list) must serialize exactly one node reference. writeEdges checks that the Collection returned for a direct edge has size == 1; a null/empty list is tolerated (written as null ref) but size != 1 throws IOException('Edge i in edges is direct, but list isn't singleton'). This almost always indicates inconsistent NodeClass edge metadata versus the node instance's actual data.","triggerScenarios":"A custom Node subclass whose NodeClass describes an edge as direct while the node stores a NodeList for it (or vice versa), so findNodes returns a multi-element collection for a direct edge. Corrupted or mismatched generated NodeClass metadata after partially regenerating node class processors. Custom findNodes/findClassEdges overrides returning the wrong collection.","commonSituations":"Hand-written node classes where the @Input/@Successor annotations and the field types (Node vs NodeList) disagree. Annotation-processor output out of sync with edited sources (stale generated metadata). Forks that customize edge introspection in GraphProtocol.","solutions":["Audit the failing node class: every direct @Input/@Successor must be a single Node field, every plural edge a NodeInputList/NodeList field.","Regenerate/clean build so the NodeClass metadata matches the annotated sources (rebuild the annotation processor output).","If you override findNodes/findClassEdges in a GraphProtocol subclass, ensure direct edges yield null or a singleton collection.","Dump with graph verification enabled (VerificationMode) to catch edge inconsistencies before serialization."],"exampleFix":"// before (metadata says direct, field is a list)\npublic class MyNode extends FixedWithNextNode {\n    @Input NodeInputList<ValueNode> args; // direct edges must be single Node fields\n}\n\n// after\npublic class MyNode extends FixedWithNextNode {\n    @Input ValueNode arg;             // direct edge: single node\n}","handlingStrategy":"try-catch","validationCode":"// before dumping, verify each node's edges agree with its NodeClass (run with -ea / verification):\n// graph.verify() catches direct-vs-list metadata inconsistencies before serialization\nif (graph.verify()) {\n    output.print(graph, ...);\n}","typeGuard":null,"tryCatchPattern":"try {\n    output.print(graph, ...);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"is direct, but list isn't singleton\")) {\n        // metadata/field mismatch in a custom node class: fix the node class, not the dumper\n        throw new IllegalStateException(\"Node edge metadata inconsistent: \" + e.getMessage(), e);\n    } else throw e;\n}","preventionTips":["Keep @Input/@Successor annotations and field types (Node vs NodeInputList) in exact agreement.","Clean-build after changing node class annotations so processor-generated NodeClass metadata is regenerated.","Run graph verification before dumping in development builds."],"tags":["java","graal","graal-compiler","graphio","nodeclass","edges","metadata-mismatch"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}