I'm writing a microservice to interact with my company's Jira server via REST API, with hopes of automating various aspects of our release process. Most of it is going fine, but I'm unable to add a comment to an issue via the REST API. When I try to do it, I receive the following error:
{
"errorMessages": [
"Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens\n at [Source: org.apache.catalina.connector.CoyoteInputStream@63d9221e; line: 1, column: 2]"
]
}
The response I get is a 400, with the following stack trace:
org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1011)
org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:819)
org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:701)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:228)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:697)
org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:448)
org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:349)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO.executeAddComment(HttpJiraDAO.kt:72)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO$addComment$1.apply(HttpJiraDAO.kt:58)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO$addComment$1.apply(HttpJiraDAO.kt:26)
au.com.ioof.asis.app.component.clients.RetryClient$Policy.lambda$null$0(RetryClient.java:137)
rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48)
rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33)
rx.Observable.unsafeSubscribe(Observable.java:10327)
rx.internal.operators.OnSubscribeRedo$2.call(OnSubscribeRedo.java:273)
rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73)
rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52)
rx.internal.operators.OnSubscribeRedo$5.request(OnSubscribeRedo.java:361)
rx.Subscriber.setProducer(Subscriber.java:211)
rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:353)
rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:47)
rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
rx.Observable.subscribe(Observable.java:10423)
rx.Observable.subscribe(Observable.java:10390)
rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443)
rx.observables.BlockingObservable.single(BlockingObservable.java:340)
au.com.ioof.asis.app.component.clients.RetryClient$Policy.execute(RetryClient.java:165)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO.addComment(HttpJiraDAO.kt:57)
au.com.ioof.asis.ocd.core.service.SignOffAuditService.auditRelease(SignOffAuditService.kt:49)
au.com.ioof.asis.ocd.resources.ReleaseStagingVerifiedResource.releaseVerified(ReleaseStagingVerifiedResource.kt:25)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:49)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:35)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:45)
io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:39)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:89)
com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:120)
com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:239)
io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:52)
org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:455)
io.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:67)
org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:56)
org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:169)
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
org.eclipse.jetty.server.Server.handle(Server.java:530)
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)
org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:289)
org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:149)
org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)
org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)
java.lang.Thread.run(Thread.java:748)
Weird thing is, I can do it through Postman just fine. This leads me to suspect that it's something unique to my code, but I can't determine what. My code is as follows:
protected fun executeAddComment(client: Client, issueId: String, comment: JiraComment) {
try {
val response = client.target(UriBuilder.fromPath("$restApi/issue/{issueId}/comment").build(issueId))
.request()
.header(HttpHeaders.AUTHORIZATION, credentials.getBase64EncodedCredentials())
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
.post(Entity.entity(comment, MediaType.APPLICATION_JSON_TYPE), Map::class.java)
} catch (e: BadRequestException) {
LOGGER.error("Stack trace: \n")
e.stackTrace.forEach {
LOGGER.error(it.toString())
}
throw e
}
}
Any ideas? I'm happy to post any other bits of my code you need. The Jira Server version I'm POSTing to is 7.7.2. I can also provide versions of any Java libraries I'm using that you're curious about.
Problem solved. It turns out that the framework code I was using Gzips requests under the hood, and I had no idea. Hence the Jira REST API was trying to parse a zipped request as JSON, and failing to parse it. A better error message would probably be helpful, but I don't know if that's something that can be controlled by the Jira REST API.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.