{"record":{"id":"b5b67bcb130cd1b6","repo":"OpenFeign/feign","slug":"eventtimeout-must-not-be-negative-eventtimeout","errorCode":null,"errorMessage":"eventTimeout must not be negative: ${eventTimeout}","messagePattern":"eventTimeout must not be negative: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"graphql/src/main/java/feign/graphql/GraphqlDecoder.java","lineNumber":58,"sourceCode":"import java.util.stream.Stream;\n\n@Experimental\npublic class GraphqlDecoder implements Decoder {\n\n  /** How long a blocking subscription call waits for an event before giving up. */\n  public static final Duration DEFAULT_EVENT_TIMEOUT = Duration.ofSeconds(60);\n\n  private final JsonDecoder jsonDecoder;\n  private final long eventTimeoutMillis;\n  private final Executor executor;\n\n  public GraphqlDecoder(JsonDecoder jsonDecoder) {\n    this(jsonDecoder, DEFAULT_EVENT_TIMEOUT, Runnable::run);\n  }\n\n  public GraphqlDecoder(JsonDecoder jsonDecoder, Duration eventTimeout, Executor executor) {\n    if (eventTimeout.isNegative()) {\n      throw new IllegalArgumentException(\"eventTimeout must not be negative: \" + eventTimeout);\n    }\n    this.jsonDecoder = jsonDecoder;\n    this.eventTimeoutMillis = eventTimeout.toMillis();\n    this.executor = executor;\n  }\n\n  @Override\n  public Object decode(Response response, Type type) throws IOException {\n    if (response.body() instanceof Subscription subscription) {\n      return subscribe(subscription, type);\n    }\n\n    Type targetType = type;\n    boolean optional = isOptionalType(type);\n    if (optional) {\n      targetType = extractOptionalInnerType(type);\n    }\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/graphql/src/main/java/feign/graphql/GraphqlDecoder.java#L40-L76","documentation":"GraphqlDecoder's constructor validates the subscription event timeout: a negative Duration is nonsensical (no events could ever be delivered in negative time), so it fails fast with IllegalArgumentException.","triggerScenarios":"new GraphqlDecoder(jsonDecoder, Duration.ofSeconds(-1), executor) or any negative Duration passed as eventTimeout; typically from misread config (e.g. '-1' meaning 'disable') or a computed duration that went negative (end before start).","commonSituations":"Configuration property like graphql.eventTimeout=-1 intended as 'infinite', or subtracting timestamps to compute a timeout without clamping.","solutions":["Pass a zero or positive Duration; use Duration.ZERO if you want no timeout","Clamp computed durations: Duration.ofMillis(Math.max(0, computedMillis))","Interpret 'disabled' config values explicitly rather than encoding them as negative durations"],"exampleFix":"// before\nGraphqlDecoder d = new GraphqlDecoder(json, Duration.parse(cfg.timeout), exec); // -1s\n// after\nDuration t = Duration.parse(cfg.timeout);\nGraphqlDecoder d = new GraphqlDecoder(json, t.isNegative() ? Duration.ZERO : t, exec);","handlingStrategy":"validation","validationCode":"Duration t = Duration.parse(cfg.timeout());\nif (t.isNegative()) t = Duration.ZERO; // or fail fast with a clear message","typeGuard":null,"tryCatchPattern":"try {\n  return new GraphqlDecoder(json, timeout, executor);\n} catch (IllegalArgumentException e) {\n  throw new ConfigException(\"eventTimeout must be >= 0, got: \" + timeout);\n}","preventionTips":["Clamp or validate durations loaded from config before constructing decoders","Never use negative durations to encode 'disabled'; use Duration.ZERO or Optional","Add unit tests for edge-case config values (0, -1)"],"tags":["graphql","configuration","duration","illegal-argument"],"backgroundTag":"invalid-argument-value","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"}