Skip to content

Filter reactor traceback from problem responses#522

Open
yawkat wants to merge 2 commits into4.0.xfrom
fix-11817-problem-debug-traceback
Open

Filter reactor traceback from problem responses#522
yawkat wants to merge 2 commits into4.0.xfrom
fix-11817-problem-debug-traceback

Conversation

@yawkat
Copy link
Copy Markdown
Member

@yawkat yawkat commented Mar 17, 2026

Summary

  • filter Reactor FluxOnAssembly$OnAssemblyException entries from the suppressed property in problem-json responses
  • add a Kotlin regression for a suspend endpoint throwing Problem under Hooks.onOperatorDebug()
  • keep the change local to ProblemJsonErrorResponseBodyProvider without adding a Reactor production dependency

Verification

  • ./gradlew :test-suite-kotlin:test --tests 'io.micronaut.problem.TaskNotFoundProblemTest' --stacktrace
  • ./gradlew :test-suite-serde-java:test --tests 'io.micronaut.problem.ProblemSerdeTest' :test-suite:test --tests 'io.micronaut.problem.OutOfStockTest' --stacktrace

Fixes #11817

Co-Authored-By: OpenCode <agent@ohmyopencode.com>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
55.6% Coverage on New Code (required ≥ 70%)
1 New Bugs (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

testAnnotationProcessor(mnSerde.micronaut.serde.processor)
testImplementation mnValidation.micronaut.validation
testImplementation libs.kotlin.stdlib.jdk8
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of defining a d dependency, it should use the one managed in core https://github.com/micronaut-projects/micronaut-core/blob/5.0.x/gradle/libs.versions.toml#L84

testImplementation mnValidation.micronaut.validation
testImplementation libs.kotlin.stdlib.jdk8
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2'
testImplementation 'io.projectreactor:reactor-core:3.5.0'
Copy link
Copy Markdown
Contributor

@sdelamo sdelamo Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of defining the reactor dependency it should use Micronaut Project reactor and don't define a version.

@sdelamo sdelamo added the type: bug Something isn't working label Apr 16, 2026
@sdelamo sdelamo moved this to In Progress in 5.0.0 Release Apr 16, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Filters Reactor FluxOnAssembly$OnAssemblyException entries out of suppressed in application/problem+json responses to avoid leaking operator-debug traceback details, and adds a Kotlin regression test covering a suspend endpoint under Hooks.onOperatorDebug().

Changes:

  • Filter Reactor on-assembly suppressed exceptions during Problem JSON serialization (without adding a Reactor production dependency).
  • Add a Kotlin suspend /product/debug endpoint that throws a Problem to reproduce operator-debug suppressed behavior.
  • Add a Kotlin regression test asserting the response does not include a suppressed field in operator debug mode.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
test-suite-kotlin/src/test/kotlin/io/micronaut/problem/TaskNotFoundProblemTest.kt Adds regression test enabling Reactor operator debug and asserting suppressed does not leak in problem responses.
test-suite-kotlin/src/test/kotlin/io/micronaut/problem/ProductController.kt Adds suspend /product/debug endpoint that throws a Problem to exercise the operator-debug suppressed-path.
test-suite-kotlin/build.gradle Adds test-scope dependencies for coroutines and reactor-core needed by the new Kotlin test/controller code.
problem-json/src/main/java/io/micronaut/problem/ProblemJsonErrorResponseBodyProvider.java Filters suppressed to drop Reactor FluxOnAssembly$OnAssemblyException and omits the field when empty.

client.exchange(request, String::class.java)
}

Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.response.contentType.get() is used without first asserting contentType.isPresent, so if the response ever lacks a content type this test will fail with a NoSuchElementException rather than a clear assertion failure. Add an assertTrue(e.response.contentType.isPresent) (or use orElseThrow with a message) before dereferencing.

Suggested change
Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Assertions.assertTrue(e.response.contentType.isPresent)

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +72
client.exchange(request, String::class.java)
}

Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Assertions.assertEquals("application/problem+json", e.response.contentType.get().toString())

val body = e.response.getBody(String::class.java)
Assertions.assertTrue(body.isPresent)
Assertions.assertTrue(body.get().contains("\"type\":\"about:blank\""))
Assertions.assertTrue(body.get().contains("\"title\":\"Validation error\""))
Assertions.assertTrue(body.get().contains("\"status\":400"))
Assertions.assertFalse(body.get().contains("\"suppressed\""))
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regression assertions rely on raw JSON substring matching (e.g. contains("\"type\":\"about:blank\"")), which is brittle with respect to serialization ordering/escaping and can cause flaky tests. Consider parsing the body as a map/JSON tree and asserting suppressed is absent (and that type/title/status have the expected values).

Suggested change
client.exchange(request, String::class.java)
}
Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Assertions.assertEquals("application/problem+json", e.response.contentType.get().toString())
val body = e.response.getBody(String::class.java)
Assertions.assertTrue(body.isPresent)
Assertions.assertTrue(body.get().contains("\"type\":\"about:blank\""))
Assertions.assertTrue(body.get().contains("\"title\":\"Validation error\""))
Assertions.assertTrue(body.get().contains("\"status\":400"))
Assertions.assertFalse(body.get().contains("\"suppressed\""))
client.exchange(request, Map::class.java)
}
Assertions.assertEquals(HttpStatus.BAD_REQUEST, e.status)
Assertions.assertEquals("application/problem+json", e.response.contentType.get().toString())
val bodyOptional = e.response.getBody(Map::class.java)
Assertions.assertTrue(bodyOptional.isPresent)
Assertions.assertEquals("about:blank", bodyOptional.get()["type"])
Assertions.assertEquals("Validation error", bodyOptional.get()["title"])
Assertions.assertEquals(400, bodyOptional.get()["status"])
Assertions.assertFalse(bodyOptional.get().containsKey("suppressed"))

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +18
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2'
testImplementation 'io.projectreactor:reactor-core:3.5.0'
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module adds new dependencies using hard-coded versions. Elsewhere in this repo test modules consistently rely on the Micronaut catalogs / version catalog (e.g. test-suite/build.gradle) to avoid version drift and unintended downgrades/upgrades. Please add these to gradle/libs.versions.toml (or use the appropriate mn... coordinates if available) and reference them via libs/catalog aliases instead of pinning versions inline.

Suggested change
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2'
testImplementation 'io.projectreactor:reactor-core:3.5.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm'
testImplementation 'io.projectreactor:reactor-core'

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Something isn't working

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants