{"record":{"id":"a537115b46a6b329","repo":"eclipse-vertx/vert.x","slug":"context-must-not-be-null","errorCode":null,"errorMessage":"context must not be null","messagePattern":"context must not be null","errorType":"exception","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/streams/impl/InboundBuffer.java","lineNumber":89,"sourceCode":"\n  private final ContextInternal context;\n  private ArrayDeque<E> pending;\n  private final long highWaterMark;\n  private long demand;\n  private Handler<E> handler;\n  private boolean overflow;\n  private Handler<Void> drainHandler;\n  private Handler<Void> emptyHandler;\n  private Handler<Throwable> exceptionHandler;\n  private boolean emitting;\n\n  public InboundBuffer(Context context) {\n    this(context, 16L);\n  }\n\n  public InboundBuffer(Context context, long highWaterMark) {\n    if (context == null) {\n      throw new NullPointerException(\"context must not be null\");\n    }\n    if (highWaterMark < 0) {\n      throw new IllegalArgumentException(\"highWaterMark \" + highWaterMark + \" >= 0\");\n    }\n    this.context = (ContextInternal) context;\n    this.highWaterMark = highWaterMark;\n    this.demand = Long.MAX_VALUE;\n    // empty ArrayDeque's constructor ArrayDeque allocates 16 elements; let's delay the allocation to be of the proper size\n    this.pending = null;\n  }\n\n  private void checkThread() {\n    if (!context.inThread()) {\n      throw new IllegalStateException(\"This operation must be called from a Vert.x thread\");\n    }\n  }\n\n  /**","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/streams/impl/InboundBuffer.java#L71-L107","documentation":"InboundBuffer is Vert.x's internal buffering queue for ReadStream implementations; it requires a Vert.x context to run handlers on. The constructor throws NullPointerException immediately when passed a null Context, since all buffering, demand accounting, and handler delivery depend on it.","triggerScenarios":"Passing null as the Context argument to new InboundBuffer(context) or new InboundBuffer(context, highWaterMark) — typically inside a custom ReadStream implementation that has no attached context (e.g. constructed outside vertx.getOrCreateContext() or before deployment).","commonSituations":"Writing a custom ReadStream and creating the InboundBuffer in a field initializer or plain constructor where no Vert.x context exists yet; using Vert.x objects created with Vertx.vertexContext() absent (embedded/standalone usage).","solutions":["Create the InboundBuffer only after a context exists: call vertx.getOrCreateContext() and pass the result","Construct the InboundBuffer lazily inside the first read/handler call instead of in a constructor/field initializer","Pass the ContextInternal captured during stream init (as core ReadStream impls do)"],"exampleFix":"// before\nthis.inboundBuffer = new InboundBuffer(null);\n// after\nContextInternal ctx = (ContextInternal) vertx.getOrCreateContext();\nthis.inboundBuffer = new InboundBuffer(ctx);","handlingStrategy":"validation","validationCode":"if (context == null) {\n  context = vertx.getOrCreateContext();\n}\nInboundBuffer buf = new InboundBuffer(context);","typeGuard":"boolean hasContext(Context c) { return c != null; }","tryCatchPattern":"try {\n  new InboundBuffer(ctx);\n} catch (NullPointerException e) {\n  // create context and retry\n}","preventionTips":["Construct InboundBuffer lazily, after the stream is attached to a context","Use vertx.getOrCreateContext() at construction sites","Never create Vert.x stream machinery in plain static initializers"],"tags":["streams","null","context","vertx"],"backgroundTag":"null-argument","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}