{"record":{"id":"05acb0eace94e6b0","repo":"oracle/graal","slug":"s-s-s-s","errorCode":null,"errorMessage":"%s %s.%s(%s)","messagePattern":"%s %s\\.%s\\(%s\\)","errorType":"exception","errorClass":"NoSuchMethodException","httpStatus":null,"severity":"error","filePath":"espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/FrameRecordSerializer.java","lineNumber":317,"sourceCode":"        Class<?>[] argTypes = new Class<?>[numArgs];\n        for (int i = 0; i < numArgs; i++) {\n            argTypes[i] = readClass(classLoader);\n        }\n\n        for (Method method : declaringClass.getDeclaredMethods()) {\n            if (!method.getName().equals(name)) {\n                continue;\n            }\n            if (!Arrays.equals(method.getParameterTypes(), argTypes)) {\n                continue;\n            }\n            if (!method.getReturnType().equals(returnType)) {\n                continue;\n            }\n            return method;\n        }\n\n        throw new NoSuchMethodException(\"%s %s.%s(%s)\".formatted(\n                        returnType.getName(), declaringClass.getName(), name, String.join(\", \", Arrays.stream(argTypes).map(Class::getName).toList())));\n    }\n\n    private Class<?> readClass(ClassLoader classLoader) throws IOException, ClassNotFoundException {\n        assert in != null;\n        int kind = in.readUnsignedByte();\n        return switch (kind) {\n            case 'I' -> int.class;\n            case 'Z' -> boolean.class;\n            case 'D' -> double.class;\n            case 'F' -> float.class;\n            case 'J' -> long.class;\n            case 'B' -> byte.class;\n            case 'C' -> char.class;\n            case 'S' -> short.class;\n            case 'V' -> void.class;\n            case 'L' -> Class.forName(readString(), false, classLoader);\n            default -> throw new IOException(\"Unexpected kind: \" + kind);","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/FrameRecordSerializer.java#L299-L335","documentation":"A NoSuchMethodException whose message is a full method signature ('returnType holder.name(argTypes)'), thrown from readMethodNameAndTypes after reflection over the deserialized holder class found no method matching the recorded name, parameter types, and return type. The serializer stores enough type information to relocate the exact Method, so this fires when the class on the reading side no longer has that exact method — a binary-compatibility break between the writing and reading runtimes.","triggerScenarios":"Serializing a continuation with method M(int)→String on the stack, deploying a new build where M was renamed, gained/lost parameters, changed return type, or moved to a superclass, then deserializing the old payload.","commonSituations":"Rolling deployments where in-flight continuations are migrated between versions; refactoring (rename method, change signature) while persisted continuations still reference the old shape; different compiler generating bridge/synthetic methods on one side only.","solutions":["Restore binary compatibility for the method named in the exception (same name, parameter types, return type) on the reading side, then retry deserialize.","If the method legitimately changed, drain or discard in-flight continuations before deploying (do not migrate across incompatible builds).","Keep the exact signature in mind: return type participates in the match — a covariant change alone breaks it.","Include continuation-payload compatibility in your deployment checklist: any method on a suspendable stack is now a serialization contract."],"exampleFix":"// before\n// v1 stack: com.acme.Task.run(Request) -> void; v2 deployed with run(Request, Context)\nContinuation.deserialize(v1Payload, loader); // NoSuchMethodException: void com.acme.Task.run(com.acme.Request)\n\n// after\n// v2 keeps the old signature and overloads instead\npublic void run(Request req)            { run(req, defaultContext()); }\npublic void run(Request req, Context c) { ... }","handlingStrategy":"validation","validationCode":"// before resume, verify the exact method still exists\nClass<?> holder = Class.forName(frameHolderName, false, loader);\nfor (Method m : holder.getDeclaredMethods()) {\n    if (m.getName().equals(recordedName) && Arrays.equals(m.getParameterTypes(), recordedArgs)\n            && m.getReturnType() == recordedReturn) { return; } // compatible\n}\nthrow new IllegalStateException(\"Incompatible deployment: \" + recordedSignature + \" missing\");","typeGuard":null,"tryCatchPattern":"try { Continuation.deserialize(bytes, loader); } catch (IOException e) { if (e.getCause() instanceof NoSuchMethodException nsme) { /* binary-incompatible build: drain in-flight continuations before deploy */ } }","preventionTips":["Keep the exact signatures (name, params, return type) of suspendable-stack methods stable across releases.","Drain or expire persisted continuations before deploying incompatible builds.","Remember return type participates in the method match — covariant changes break deserialization."],"tags":["serialization","continuations","reflection","binary-compatibility"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}