{"record":{"id":"fb127f6a03c19e4b","repo":"clojure/clojure","slug":"method-too-large-classname-methodname-des","errorCode":null,"errorMessage":"Method too large: ${className}.${methodName} ${descriptor}","messagePattern":"Method too large: (.+?)\\.(.+?) (.+?)","errorType":"exception","errorClass":"MethodTooLargeException","httpStatus":null,"severity":"error","filePath":"src/jvm/clojure/asm/MethodWriter.java","lineNumber":2087,"sourceCode":"\n  /**\n   * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the\n   * names of the attributes of this method in the constant pool.\n   *\n   * @return the size in bytes of the method_info JVMS structure.\n   */\n  int computeMethodInfoSize() {\n    // If this method_info must be copied from an existing one, the size computation is trivial.\n    if (sourceOffset != 0) {\n      // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index.\n      return 6 + sourceLength;\n    }\n    // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count.\n    int size = 8;\n    // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.\n    if (code.length > 0) {\n      if (code.length > 65535) {\n        throw new MethodTooLargeException(\n                symbolTable.getClassName(), name, descriptor, code.length);\n      }\n      symbolTable.addConstantUtf8(Constants.CODE);\n      // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,\n      // max_locals, code_length and attributes_count, plus the bytecode and the exception table.\n      size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);\n      if (stackMapTableEntries != null) {\n        boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6;\n        symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : \"StackMap\");\n        // 6 header bytes and 2 bytes for number_of_entries.\n        size += 8 + stackMapTableEntries.length;\n      }\n      if (lineNumberTable != null) {\n        symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE);\n        // 6 header bytes and 2 bytes for line_number_table_length.\n        size += 8 + lineNumberTable.length;\n      }\n      if (localVariableTable != null) {","sourceCodeStart":2069,"sourceCodeEnd":2105,"githubUrl":"https://github.com/clojure/clojure/blob/f3b143341d6efc6428b523b2eaa099a6cc99156e/src/jvm/clojure/asm/MethodWriter.java#L2069-L2105","documentation":"The JVM's class file format stores the Code attribute length in a 2-byte unsigned short, so any single method's bytecode may not exceed 65535 bytes. During ClassWriter.toByteArray(), MethodWriter detects code.length > 65535 and throws MethodTooLargeException naming the class, method and descriptor; this means the generator produced too much bytecode for one method, not that a parameter is wrong.","triggerScenarios":"Dynamic class generation or instrumentation that creates one huge method: giant switch/string dispatch, deeply inlined generated code, a huge static initializer (<clinit>) with many constants, or a bytecode weaver injecting a very large block into an already-large method.","commonSituations":"Compilers for DSLs (rule engines, query builders, protobuf-like serializers) generating one method per schema; test-code generators creating thousands of asserts in one method; annotation processors inlining large templates; instrumenting large legacy methods with substantial added prologue code.","solutions":["Split the generated code across multiple private helper methods invoked from the main one.","Move large constant tables/data into static fields, arrays or resources loaded at runtime instead of inlined instructions.","Reduce instrumentation scope: wrap the original method body in a try or delegate to a generated helper instead of inlining logic.","For javac inputs, refactor the source method (extract methods, replace long switch chains with map lookups) and recompile.","Use invokedynamic/MethodHandles to dispatch dynamically instead of generating huge switch statements."],"exampleFix":"// before: emit every case inline in one giant method\nfor (Rule r : rules) { generateCaseInline(mv, r); } // >65535 bytes -> MethodTooLargeException\n// after\ngenerateDispatch(mv, rules); // emits tableswitch calling generated helpers\nfor (Rule r : rules) {\n  MethodVisitor h = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, \"rule$\" + r.id, \"()V\", null, null);\n  generateCaseInline(h, r);\n}","handlingStrategy":"try-catch","validationCode":"// Track approximate generated size while emitting; bail out early\nprivate int approxBytes = 0;\nvoid emit(Consumer<MethodVisitor> op, int estimatedBytes) {\n  if (approxBytes + estimatedBytes > 60000) {\n    throw new IllegalStateException(\"Generated method nearing 64KB code limit; split it\");\n  }\n  approxBytes += estimatedBytes;\n  op.accept(mv);\n}\n","typeGuard":null,"tryCatchPattern":"try {\n  byte[] classBytes = classWriter.toByteArray();\n} catch (MethodTooLargeException e) {\n  // e gives className, methodName, descriptor, codeSize\n  throw new IllegalStateException(\n    \"Split generated method \" + e.getMethodName() + \" (code size \" + e.getCodeSize() + \") into helpers\", e);\n}","preventionTips":["Design generators to emit one helper method per logical block instead of one huge method.","Store large constant pools/data as static fields or resources rather than inlined instructions.","Estimate emitted instruction size for huge switches/loops and split before the 65535-byte limit.","For javac-produced code, keep source methods small (extract methods, replace long switch chains)."],"tags":["asm","bytecode","limit-exceeded","code-generation"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"f3b143341d6efc6428b523b2eaa099a6cc99156e","analyzedAt":"2026-09-09T12:04:58.961Z","contentChangedAt":"2026-09-09T12:04:58.961Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}