{"record":{"id":"9e820240681e6f67","repo":"eclipse-vertx/vert.x","slug":"read-only","errorCode":null,"errorMessage":"Read only","messagePattern":"Read only","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/headers/HeadersAdaptor.java","lineNumber":72,"sourceCode":"  @Override\n  public boolean contains(String name) {\n    return headers.contains(name);\n  }\n\n  @Override\n  public boolean isEmpty() {\n    return headers.isEmpty();\n  }\n\n  @Override\n  public Set<String> names() {\n    return headers.names();\n  }\n\n  @Override\n  public HeadersAdaptor add(String name, String value) {\n    if (!mutable) {\n      throw new IllegalStateException(\"Read only\");\n    }\n    headers.add(name, value);\n    return this;\n  }\n\n  @Override\n  public HeadersAdaptor add(String name, Iterable<String> values) {\n    if (!mutable) {\n      throw new IllegalStateException(\"Read only\");\n    }\n    headers.add(name, values);\n    return this;\n  }\n\n  @Override\n  public HeadersAdaptor addAll(MultiMap headers) {\n    for (Map.Entry<String, String> entry: headers.entries()) {\n      add(entry.getKey(), entry.getValue());","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/headers/HeadersAdaptor.java#L54-L90","documentation":"HeadersAdaptor wraps an existing HttpHeaders instance and can be created read-only (mutable=false). All mutating operations throw IllegalStateException(\"Read only\") when the adaptor is not mutable. add(String,String) is one of those guarded mutators, invoked directly or via addAll/setAll.","triggerScenarios":"Calling headersMultiMap.add(\"k\",\"v\") on an adaptor obtained from a read-only source, e.g. request.headers() style views built as new HeadersAdaptor(headers, false), or calling addAll/add on a shared immutable headers view.","commonSituations":"Trying to modify response/request headers through a cached or shared read-only headers snapshot; wrapping server-supplied headers with a non-mutable adaptor and then attempting to append a value; framework code (addAll/setAll) delegating into add and hitting the guard.","solutions":["Create a mutable copy first: new HeadersMultiMap().addAll(readOnlyHeaders) or HttpHeaders with an empty MultiMap and copy entries","If you own the adaptor construction, create it with mutable=true","Use the underlying object's own mutable API if the wrapper is intentionally read-only","Don't expose read-only adaptors to code that mutates them; document ownership"],"exampleFix":"// before\nreadOnlyHeaders.add(\"X-Custom\", \"v\"); // IllegalStateException\n// after\nio.vertx.core.MultiMap mutable = io.vertx.core.MultiMap.caseInsensitiveMultiMap();\nmutable.addAll(readOnlyHeaders);\nmutable.add(\"X-Custom\", \"v\");","handlingStrategy":"validation","validationCode":"if (!isMutable(headers)) {\n  headers = io.vertx.core.MultiMap.caseInsensitiveMultiMap().addAll(headers);\n}\nheaders.add(\"X-Custom\", \"v\");","typeGuard":"static boolean isMutable(io.vertx.core.MultiMap m) { return !(m instanceof io.vertx.core.http.impl.headers.HeadersAdaptor) || true; // adaptor exposes no mutability flag; treat unknown/IO-sourced views as read-only","tryCatchPattern":"try {\n  headers.add(name, value);\n} catch (IllegalStateException e) {\n  if (\"Read only\".equals(e.getMessage())) {\n    headers = io.vertx.core.MultiMap.caseInsensitiveMultiMap().addAll(headers);\n    headers.add(name, value);\n  } else throw e;\n}","preventionTips":["Treat request.headers() style views as immutable; copy before mutating","Document ownership of MultiMap instances in middleware chains","Centralize header mutation in helpers that always work on a fresh mutable MultiMap","Never reuse cached header snapshots as scratch buffers"],"tags":["headers","http","immutability"],"backgroundTag":"unsupported-operation","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}