Adding JSON to BLOB description causes an error 500
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 28
- Forks
- 25
- Avg merge
- 4d 22h
- Merged PRs (30d)
- 20
Description
Describe the bug
If you try to save JSON (not a string, but a serialized JSON object) to the description field when storing a BLOB, an error 500 is returned, and the log contains a serialization error.
Expected behavior
Either ignoring the deserialization of that field, or capture and return a more appropriate error message.
To Reproduce
public static void storeBinary(String name, byte[] object, String mime_type, String comment, URL cdaUrl, String cdaKey, String cdaOffice) throws IOException, InterruptedException {
JsonObject desc = new JsonObject();
desc.put("last-modified", Instant.now().toEpochMilli());
if(comment != null && !comment.equals(""))
desc.put("comment", comment);
JsonObject body = new JsonObject();
body.put("office-id", cdaOffice);
body.put("id", name);
body.put("media-type-id", mime_type);
body.put("description", desc);
body.put("value", Base64.getMimeEncoder().encodeToString(object));
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create(cdaUrl.toString() + "/blobs?fail-if-exists=false"))
.header("Authorization", "apikey " + cdaKey)
.POST(BodyPublishers.ofString(body.toJson()))
.build();
logger.info("Storing binary in CDA: " + name);
var response = client.send(request, BodyHandlers.ofString());
if(response.statusCode() != 200)
{
throw new IOException("Error saving binary to " + request.uri().toString() + ": " + response.statusCode() + " " + response.body());
}
}
Logs/Incident Identifier
17-Apr-2026 18:04:15.170 SEVERE [ajp-nio-127.0.0.1-8009-exec-900] cwms.cda.ApiServlet.lambda$init$3 eb444fa7-ae59-475e-a1e8-3d0ac486c20d: Formatting error:Could not deserialize: org.apache.catalina.connector.CoyoteInputStream@7194fc46 of
type: class cwms.cda.data.dto.Blob. Originates from Parser
cwms.cda.formatters.FormattingException: Could not deserialize: org.apache.catalina.connector.CoyoteInputStream@7194fc46 of type: class cwms.cda.data.dto.Blob
at cwms.cda.formatters.json.JsonV2.parseContent(JsonV2.java:117)
at cwms.cda.formatters.Formats.parseContentFromType(Formats.java:165)
at cwms.cda.formatters.Formats.parseContent(Formats.java:241)
at cwms.cda.api.BlobController.create(BlobController.java:206)
at io.javalin.apibuilder.CrudFunction$3.invoke$lambda-0(CrudHandler.kt:32)
at io.javalin.apibuilder.CrudFunctionHandler.handle(CrudHandler.kt)
at cwms.cda.security.CdaAccessManager.manage(CdaAccessManager.java:37)
at io.javalin.http.JavalinServlet.addHandler$lambda-0(JavalinServlet.kt:96)
at io.javalin.http.JavalinServlet$lifecycle$2$1$1.invoke(JavalinServlet.kt:43)
at io.javalin.http.JavalinServlet$lifecycle$2$1$1.invoke(JavalinServlet.kt:43)
at io.javalin.http.JavalinServletHandler.executeNextTask(JavalinServletHandler.kt:99)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$lambda-1(JavalinServletHandler.kt:85)
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1106)
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2235)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$javalin(JavalinServletHandler.kt:85)
at io.javalin.http.JavalinServletHandler.executeNextTask$lambda-11$lambda-10(JavalinServletHandler.kt:119)
at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680)
at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658)
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094)
at io.javalin.http.JavalinServletHandler.executeNextTask(JavalinServletHandler.kt:119)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$lambda-1(JavalinServletHandler.kt:85)
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1106)
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2235)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$javalin(JavalinServletHandler.kt:85)
at io.javalin.http.JavalinServletHandler.executeNextTask$lambda-11$lambda-10(JavalinServletHandler.kt:119)
at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680)
at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658)
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094)
at io.javalin.http.JavalinServletHandler.executeNextTask(JavalinServletHandler.kt:119)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$lambda-1(JavalinServletHandler.kt:85)
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1106)
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2235)
at io.javalin.http.JavalinServletHandler.queueNextTaskOrFinish$javalin(JavalinServletHandler.kt:85)
at io.javalin.http.JavalinServlet.service(JavalinServlet.kt:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
at cwms.cda.ApiServlet.service(ApiServlet.java:920)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:197)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:142)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:142)
at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:129)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:142)
at org.apache.catalina.filters.CorsFilter.handleNonCORS(CorsFilter.java:334)
at org.apache.catalina.filters.CorsFilter.doFilter(CorsFilter.java:161)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:142)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:88)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:596)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:643)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:643)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:83)
at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:72)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:429)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:935)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1831)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:973)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:491)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 34] (through reference chain: cwms.cda.data.dto.Blob["description"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1767)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1541)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1446)
at com.fasterxml.jackson.databind.DeserializationContext.extractScalarFromObject(DeserializationContext.java:958)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseString(StdDeserializer.java:1441)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:48)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:310)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4905)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3885)
at cwms.cda.formatters.json.JsonV2.parseContent(JsonV2.java:115)
... 68 more
CDA Version (please complete the following information):
At the top of any instance of CDA you will see a version. Please provide that version.
- Version 2023.03.31
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with cwms.cda.formatters.json.JsonV2.parseContent and the cwms.cda.data.dto.Blob field named in the deserialization error, then trace the request through BlobController.create. Reproduce the JSON description case from the issue and inspect the existing formatting error handling. Done means the request no longer produces an unexpected 500 and follows one of the documented expected behaviors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100