// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[sec:reporting_problems]]
= Reporting Plugin Problems with the Problems API
:keywords: problems, api, problem

Gradle’s Problems API lets plugins report rich, structured information about issues that occur during a failing build.

The following example shows how a plugin can report a problem:

====
include::sample[dir="snippets/reference/plugin-development/problemReporting/kotlin/buildSrc/src/main/java/org/myorg",files="ProblemReportingPlugin.java[tags=snippet]"]
====
<1> Inject the `Problem` service into the plugin.
<2> Create a `ProblemReporter` for the plugin.
<3> Report a recoverable problem so the build can continue.
<4> Add optional extra data to the problem.

[[sec:problems_api_usage]]
== Problems API Usage

The following simple plugin adds a `greet` task:

- It prints a `Hello World` greeting when used correctly: `./gradlew greet -Precipient=World`
- It warns if no recipient is set: `./gradlew greet`
- It fails if the recipient is `fail`: `./gradlew greet -Precipient=fail`

The details of the failure will be provided in the <<sec:generated_html_report,HTML Problems Report>>:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[]"]
====

How it works:

1. **Injects the `Problems` service** into the task.
2. **Creates a `ProblemGroup`** to group related problems.
3. **Creates a `ProblemId`** for each distinct issue.
4. **Reports warnings** with the `ProblemReporter.report()` when the build can continue.
5. **Throws structured failures** with `ProblemReporter.throwing()` when the build must stop.
6. **Optionally attaches `AdditionalData`** to `ProblemSpec` so advanced tools can show extra info.

[[injecting_the_problems_service]]
=== Injecting the `Problems` service

Gradle will automatically provide the link:{javaDocPath}/org/gradle/api/problems/Problems.html[`Problems`] service when injected into the custom task type:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-service]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-service]"]
====

[[creating_a_problem_id_and_problem_group]]
=== Creating a `ProblemId` and `ProblemGroup`

Problem IDs and Groups help Gradle deduplicate, summarize, and link to solutions:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-id]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-id]"]
====

[[choosing_a_reporting_mode]]
=== Choosing a reporting mode for the `ProblemReporter`

Plugins can report problems in two ways:

- link:{javadocPath}/org/gradle/api/problems/ProblemReporter.html#reporting-org.gradle.api.Action-[`report()`] — use for recoverable problems when the build should continue.
- link:{javadocPath}/org/gradle/api/problems/ProblemReporter.html#throwing-org.gradle.api.Action-[`throwing()`] — use for non-recoverable problems that should fail the build.

Once you have decided what type of problem you want to report, get the link:{javaDocPath}/org/gradle/api/problems/ProblemReporter.html[`ProblemReporter`] using `problem.getReporter()`:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-reporter]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-reporter]"]
====

[[reporting_a_recoverable_problem]]
==== Reporting a recoverable problem

Use `problems.getReporter().report {}` to signal something went wrong but allow the build to continue:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-report]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-report]"]
====

[[reporting_a_fatal_problem]]
==== Reporting a fatal problem

Use `problems.getReporter().throwing {}` to fail the build with a structured error:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-throw]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-throw]"]
====

This throws an exception tied to a rich problem report so Gradle clients can display meaningful failure info.

[[add_data_using_problem_spec]]
=== Add data using `ProblemSpec`

When reporting a problem, you can provide a wide variety of metadata such as descriptions, severity, solutions, and additional data:

====
include::sample[dir="snippets/reference/plugin-development/reportingProblems/kotlin",files="plugin/src/main/kotlin/org/example/HelloProblemsPlugin.kt[tags=problems-spec]"]
include::sample[dir="snippets/reference/plugin-development/reportingProblems/groovy",files="plugin/src/main/groovy/org/example/HelloProblemsPlugin.groovy[tags=problems-spec]"]
====

See link:{javaDocPath}/org/gradle/api/problems/ProblemSpec.html[`ProblemSpec`] for all available fields.

[[sec:problem_summarization]]
== Problem Summarization

Gradle avoids spamming users with duplicate problem messages:

- The first few instances of a problem are reported individually as link:{javaDocPath}/org/gradle/tooling/events/problems/Problem.html[`Problem`] events.
- Subsequent duplicates are summarized at the end of the build as a link:{javaDocPath}/org/gradle/tooling/events/problems/ProblemSummary.html[`ProblemSummary`], delivered with a link:{javaDocPath}/org/gradle/tooling/events/problems/ProblemSummariesEvent.html[`ProblemSummariesEvent`].

[[sec:build_failures]]
== Build Failures

The standard way to fail a build is by throwing an exception.
The Problems API enhances this by allowing you to throw exceptions tied to detailed problem reports:

====
include::sample[dir="snippets/reference/plugin-development/problems-api-usage/common/reporters/standard-plugin/src/main/java/reporters",files="FailingTask.java[tags=problems-api-fail-the-build]"]
====

This ensures build failures are clearly associated with their underlying issues and are visible across all Gradle clients (CLI, Build Scan, IDEs, Tooling API).

[[command_line_interface_problems]]
=== Command-line Interface

Gradle CLI output shows detailed information from the reported problem:

[source,text]
----
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':myFailingTask'.
> FailingTask execution problem  // <1>
    This happened because ProblemReporter.throwing() was called  // <2>
      This is a demonstration of how to add  // <3>
      detailed information to a build failure

* Try:  // <4>
> Remove the Problems.throwing() method call from the task action
> Run with --scan to generate a Build Scan (powered by Develocity).
BUILD FAILED in 0ms  // <5>
----
<1> The display name of the problem ID.
<2> The contextual label (or the supplied exception's message if the contextual label is missing).
<3> The content of the `details` property.
<4> The solutions or recommended actions.
<5> The `AdditionalData` is not shown in CLI output.

[[tooling_api_clients]]
=== Tooling API Clients

Tooling API clients can access reported problems tied to failures:

- Register a progress listener for `OperationType.ROOT`.
- Check if the result is a `FailureResult` and retrieve problems with `Failure.getProblems()`.

Alternatively, configure the project connection with `LongRunningOperation.withFailureDetails()`.
Then failure details, including problems, are automatically available via `GradleConnectionException.getFailures()`.

[[sec:generated_html_report]]
== Generated HTML Report

Gradle generates an HTML report at the end of the build if any problems were reported.
It’s a central place to review issues and complements the console and Build Scan outputs.

[NOTE]
====
To keep stack trace capture affordable, Gradle infers a source location for only a limited number of problems per build, so very large builds may list some problems without a file and line.
Run with `--warning-mode=all` or `--warning-mode=fail` to infer a location for every problem; past the cap, the trace is reduced to the originating build logic and calling script.
====

- The report is skipped if no problems are found.
- Disable report generation with the `--no-problems-report` flag.

Console output includes a link to the report:

[source,text]
----
[Incubating] Problem report is available at: <project-dir>/build/reports/problems/problems-report.html

BUILD SUCCESSFUL in 1s
----

image::problems-report-html.png[]

`AdditionalData` is not included in the HTML report.
Plugins can log their own problem events, which appear alongside Gradle’s built-in reports.

[[sec:console_rendering]]
== Console rendering

All problem reports are now rendered in the console output if `--warning-mode=all` is configured.
