{"record":{"id":"18f6b257efdd2559","repo":"openzipkin/zipkin","slug":"already-executed","errorCode":null,"errorMessage":"Already Executed","messagePattern":"Already Executed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/Call.java","lineNumber":376,"sourceCode":"    @Override public String toString() {\n      return \"ErrorHandling{call=\" + delegate + \", errorHandler=\" + errorHandler + \"}\";\n    }\n\n    @Override public Call<V> clone() {\n      return new ErrorHandling<>(errorHandler, delegate.clone());\n    }\n  }\n\n  public static abstract class Base<V> extends Call<V> {\n    volatile boolean canceled;\n    boolean executed;\n\n    protected Base() {\n    }\n\n    @Override public final V execute() throws IOException {\n      synchronized (this) {\n        if (this.executed) throw new IllegalStateException(\"Already Executed\");\n        this.executed = true;\n      }\n\n      if (isCanceled()) {\n        throw new IOException(\"Canceled\");\n      } else {\n        return this.doExecute();\n      }\n    }\n\n    protected abstract V doExecute() throws IOException;\n\n    @Override public final void enqueue(Callback<V> callback) {\n      synchronized (this) {\n        if (this.executed) throw new IllegalStateException(\"Already Executed\");\n        this.executed = true;\n      }\n","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/Call.java#L358-L394","documentation":"Call.Base.execute throws IllegalStateException('Already Executed') when execute() is invoked more than once on the same Call. Zipkin Calls are one-shot, modeled after OkHttp's Request: a Call represents a single invocation, and repeated execution would double-report or race the underlying resource. The executed flag is set under synchronization so the check is thread-safe.","triggerScenarios":"Holding a Call object (e.g. from storage.getTraces(...)) and calling execute() twice, or calling execute() after enqueue() on the same instance — enqueue also flips the executed flag.","commonSituations":"Retry loops that re-run the same Call instead of creating a new one; caching Call objects; helpers that both enqueue and execute depending on a flag; sharing a Call between threads.","solutions":["Create a fresh Call for each attempt: re-invoke storage.getTraces(...) (Calls are cheap factories).","Use call.clone() if the implementation supports it to re-run an identical request.","Audit code paths where execute() and enqueue() can both run on the same Call instance."],"exampleFix":"// before\nCall<List<Span>> call = storage.getTraces(query);\nList<Span> first = call.execute();\nList<Span> retry = call.execute(); // IllegalStateException\n\n// after\nList<List<Span>> first = storage.getTraces(query).execute();\nList<List<Span>> retry = storage.getTraces(query).execute();","handlingStrategy":"validation","validationCode":"// never reuse a Call: re-create it per attempt\nCall<List<List<Span>>> attempt = storage.getTraces(query); // fresh each time","typeGuard":null,"tryCatchPattern":"try { call.execute(); } catch (IllegalStateException e) { if (\"Already Executed\".equals(e.getMessage())) { /* logic bug: re-create the Call instead */ } throw e; }","preventionTips":["Treat zipkin Call objects as single-use requests, like OkHttp","Do not cache Call fields; cache the query and mint Calls on demand","Never let execute() and enqueue() both run on one Call"],"tags":["core","call","one-shot","illegal-state","retry"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}