{"record":{"id":"128557a90317aa06","repo":"elastic/elasticsearch","slug":"transportversion-fromname-must-be-called-with-a-no","errorCode":null,"errorMessage":"TransportVersion.fromName must be called with a non-empty String literal. See {}.","messagePattern":"TransportVersion\\.fromName must be called with a non-empty String literal\\. See (.+?)\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/CollectTransportVersionReferencesTask.java","lineNumber":121,"sourceCode":"\n                    @Override\n                    public void visitLabel(Label label) {\n                        // asm uses many debug labels that we do not want to consider\n                        // so we ignore labels so they do not become part of the instructions list\n                    }\n\n                    @Override\n                    public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {\n                        if (owner.equals(TRANSPORT_VERSION_SET_CLASS) && name.equals(TRANSPORT_VERSION_SET_METHOD_NAME)) {\n                            var abstractInstruction = this.instructions.getLast();\n                            String location = classname + \" line \" + lineNumber;\n                            if (abstractInstruction instanceof LdcInsnNode ldcInsnNode\n                                && ldcInsnNode.cst instanceof String tvName\n                                && tvName.isEmpty() == false) {\n                                results.add(new TransportVersionReference(tvName, location));\n                            } else {\n                                // The instruction is not a LDC with a String constant (or an empty String), which is not allowed.\n                                throw new RuntimeException(\n                                    \"TransportVersion.fromName must be called with a non-empty String literal. \" + \"See \" + location + \".\"\n                                );\n                            }\n                        }\n                        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);\n                    }\n                };\n            }\n        };\n        ClassReader classReader = new ClassReader(classBytes);\n        classReader.accept(classVisitor, 0);\n    }\n\n    private static String classname(String filename) {\n        return filename.substring(0, filename.length() - CLASS_EXTENSION.length()).replaceAll(\"[/\\\\\\\\]\", \".\");\n    }\n}\n","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/transport/CollectTransportVersionReferencesTask.java#L103-L139","documentation":"RuntimeException from CollectTransportVersionReferencesTask's ASM bytecode visitor. It scans compiled classes for calls to TransportVersion.fromName(...) and requires the argument to be a non-empty LDC string literal (a compile-time constant). Any other shape (variable, method call result, computed value, or empty literal) is rejected because the static analysis cannot record a stable transport-version name.","triggerScenarios":"Source code calls TransportVersion.fromName(someVariable), TransportVersion.fromName(\"\"), or passes a concatenated/computed string; ASM's last instruction before the call is not an LdcInsnNode with a String constant.","commonSituations":"Refactoring a fromName call to use a constant field or a computed value; copy-pasting a fromName placeholder with an empty string; using a non-final String field (not inlined to LDC).","solutions":["Locate the call at the reported 'classname line N' and replace the argument with a non-empty string literal.","If a shared constant is needed, make it a compile-time constant (static final String literal) so javac inlines it as LDC.","Never pass dynamically-computed strings to TransportVersion.fromName."],"exampleFix":"// before\nTransportVersion v = TransportVersion.fromName(versionNameFromConfig);\n\n// after\nTransportVersion v = TransportVersion.fromName(\"my_feature_v1\");","handlingStrategy":"validation","validationCode":"// Static-analysis guard in source: only allow string literals\nstatic final Set<String> ALLOWED = Set.of(\"feature_a_v1\", \"feature_b_v1\");\nvoid register(String name) {\n    if (name == null || name.isEmpty() || !ALLOWED.contains(name)) {\n        throw new IllegalArgumentException(\"TransportVersion name must be a known literal: \" + name);\n    }\n    TransportVersion.fromName(name);\n}","typeGuard":"// Compile-time-ish guard: prevent dynamic names at review time\nstatic void assertLiteral(String name) {\n    if (name == null || name.isEmpty()) throw new IllegalArgumentException(\"empty name\");\n}","tryCatchPattern":null,"preventionTips":["Always pass a string literal to TransportVersion.fromName.","Use static final String constants so javac inlines them to LDC.","Never read version names from config/env at the call site."],"tags":["transport-version","bytecode-analysis","asm","static-analysis","build-tooling"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}