{"record":{"id":"95891eb0cacd3e20","repo":"elastic/elasticsearch","slug":"mockapmserver-already-started","errorCode":null,"errorMessage":"MockApmServer already started","messagePattern":"MockApmServer already started","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/MockApmServer.java","lineNumber":102,"sourceCode":"    private Pattern createWildcardPattern(String filter) {\n        if (filter == null || filter.isEmpty()) {\n            return null;\n        }\n        var pattern = Arrays.stream(filter.split(\",\\\\s*\"))\n            .map(Pattern::quote)\n            .map(s -> s.replace(\"*\", \"\\\\E.*\\\\Q\"))\n            .collect(Collectors.joining(\")|(\", \"(\", \")\"));\n        return Pattern.compile(pattern);\n    }\n\n    /**\n     * Start the Mock APM server. Just returns empty JSON structures for every incoming message\n     *\n     * @throws IOException\n     */\n    public void start() throws IOException {\n        if (instance != null) {\n            throw new IllegalStateException(\"MockApmServer already started\");\n        }\n        InetSocketAddress addr = new InetSocketAddress(\"0.0.0.0\", 0);\n        HttpServer server = HttpServer.create(addr, 10);\n        server.createContext(\"/\", new RootHandler());\n        server.start();\n        instance = server;\n        logger.lifecycle(\"MockApmServer started on port \" + server.getAddress().getPort());\n\n        grpcInstance = ServerBuilder.forPort(0).addService(new GrpcMetricsService()).addService(new GrpcTraceService()).build().start();\n        logger.lifecycle(\"MockApmServer gRPC (OTLP metrics + traces) started on port \" + grpcInstance.getPort());\n    }\n\n    public int getPort() {\n        if (instance == null) {\n            throw new IllegalStateException(\"MockApmServer not started\");\n        }\n        return instance.getAddress().getPort();\n    }","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/MockApmServer.java#L84-L120","documentation":"Thrown by MockApmServer.start() if the instance field is already non-null — i.e. start() was called twice on the same MockApmServer object. The server is single-use: start() binds an HttpServer on 0.0.0.0:0 and a gRPC ServerBuilder on port 0, storing references in instance/grpcInstance.","triggerScenarios":"Code calls mockServer.start() a second time without stop()/nulling the instance. In RunTask this can happen if a custom task wires start() into a lifecycle hook that fires more than once, or if the same MockApmServer instance is shared across tasks.","commonSituations":"Custom RunTask subclass that calls start() in both a doFirst and the default action; reusing a static MockApmServer across gradle tasks in the same build; a test fixture that starts APM in @BeforeAll without checking prior state.","solutions":["Call start() exactly once per MockApmServer instance — guard with 'if (mockServer == null) { mockServer = new MockApmServer(...); mockServer.start(); }'.","If you need a fresh server, call stop() first and assign a new instance.","Let RunTask own the lifecycle (apmServerEnabled flag) rather than calling start() yourself."],"exampleFix":"// before:\nmockServer.start();  // called twice → throws\n// after:\nif (mockServer == null) {\n    mockServer = new MockApmServer(metrics, txns, excludes);\n    mockServer.start();\n}","handlingStrategy":"validation","validationCode":"if (instance != null) {\n    throw new IllegalStateException(\"MockApmServer already started\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call start() exactly once per MockApmServer instance.","Guard with a null check before starting.","Let RunTask own the APM lifecycle via apmServerEnabled."],"tags":["testclusters","apm","lifecycle","api-misuse"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}