{"record":{"id":"61424e261a051393","repo":"OpenFeign/feign","slug":"method-s-of-contract-s-doesn-t-returns-io-vertx","errorCode":null,"errorMessage":"Method %s of contract %s doesn't returns io.vertx.core.Future","messagePattern":"Method (.+?) of contract (.+?) doesn't returns io\\.vertx\\.core\\.Future","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx/feign-vertx/src/main/java/feign/vertx/VertxDelegatingContract.java","lineNumber":54,"sourceCode":"  public VertxDelegatingContract(final Contract delegate) {\n    this.delegate = checkNotNull(delegate, \"delegate must not be null\");\n  }\n\n  @Override\n  public List<MethodMetadata> parseAndValidateMetadata(final Class<?> targetType) {\n    checkNotNull(targetType, \"Argument targetType must be not null\");\n\n    final List<MethodMetadata> metadatas = delegate.parseAndValidateMetadata(targetType);\n\n    for (final MethodMetadata metadata : metadatas) {\n      final Type type = metadata.returnType();\n\n      if (type instanceof ParameterizedType\n          && ((ParameterizedType) type).getRawType().equals(Future.class)) {\n        final Type actualType = resolveLastTypeParameter(type, Future.class);\n        metadata.returnType(actualType);\n      } else {\n        throw new IllegalStateException(\n            String.format(\n                \"Method %s of contract %s doesn't returns io.vertx.core.Future\",\n                metadata.configKey(), targetType.getSimpleName()));\n      }\n    }\n\n    return metadatas;\n  }\n}\n","sourceCodeStart":36,"sourceCodeEnd":64,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/vertx/feign-vertx/src/main/java/feign/vertx/VertxDelegatingContract.java#L36-L64","documentation":"VertxDelegatingContract.parseAndValidateMetadata validates at interface-parse time that every method's declared return type is a ParameterizedType whose raw type is io.vertx.core.Future. The Vert.x contract only knows how to substitute the Future's actual type argument as the Feign return type; anything else is rejected with an IllegalStateException naming the method's configKey and target type.","triggerScenarios":"Declaring a method on a contract parsed by VertxDelegatingContract whose return type is a raw Future (no type parameter), a Future subclass, or a non-Future type such as User, List<User>, CompletableFuture<User>, or void.","commonSituations":"Forgetting the generic parameter (raw Future instead of Future<User>); returning CompletableFuture/Single/Mono from a reactor/reactivex-style contract; a shared API interface reused across sync and Vert.x clients.","solutions":["Make the return type io.vertx.core.Future<ActualType> with an explicit type argument.","Remove or split out methods that do not return Future into a separate synchronous interface.","Verify the raw type is exactly io.vertx.core.Future, not a custom Future subtype.","If using reactive wrappers, use the matching integration (reactive streams modules) instead of the Vert.x contract."],"exampleFix":"// before\n@RequestLine(\"GET /items\")\nFuture listItems();\n// after\n@RequestLine(\"GET /items\")\nFuture<List<Item>> listItems();","handlingStrategy":"validation","validationCode":"for (Method m : Api.class.getDeclaredMethods()) {\n  if (!(m.getGenericReturnType() instanceof ParameterizedType)\n      || ((ParameterizedType) m.getGenericReturnType()).getRawType() != io.vertx.core.Future.class) {\n    throw new IllegalStateException(m + \" must return io.vertx.core.Future<T>\");\n  }\n}","typeGuard":"static boolean isParameterizedFuture(Type t) {\n  return t instanceof ParameterizedType\n      && ((ParameterizedType) t).getRawType() == io.vertx.core.Future.class;\n}","tryCatchPattern":"try {\n  VertxVertx.feign().target(Api.class, baseUrl);\n} catch (IllegalStateException e) {\n  // contract parse failure: a method lacks a parameterized Future return type\n}","preventionTips":["Never use raw Future as a return type; always supply the type parameter","Keep non-Future methods in a separate interface used only with the default contract","Create the proxy in application startup code so invalid contracts fail fast"],"tags":["vertx","contract","validation","generics"],"backgroundTag":"type-mismatch","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}