Skip to content

SONARJAVA-6053 Fix S112 false positive for checked exception wrappers#5592

Draft
sonar-nigel[bot] wants to merge 6 commits into
masterfrom
fix/SONARJAVA-6053-fix-fp-on-s112-exception-wrapping-in-runtimeexception-for-checked-exceptions-gpt-5.5
Draft

SONARJAVA-6053 Fix S112 false positive for checked exception wrappers#5592
sonar-nigel[bot] wants to merge 6 commits into
masterfrom
fix/SONARJAVA-6053-fix-fp-on-s112-exception-wrapping-in-runtimeexception-for-checked-exceptions-gpt-5.5

Conversation

@sonar-nigel
Copy link
Copy Markdown
Contributor

@sonar-nigel sonar-nigel Bot commented May 1, 2026

Relates to SONARJAVA-6053

Suppress S112 when RuntimeException or Error is used in a catch block to wrap a specific checked exception as the cause, while keeping existing reports for broad generic throws and wrappers that do not preserve the caught cause.

  • Keeps throws clause reporting unchanged.
  • Requires the catch type to be a specific checked exception, including each multi-catch alternative.
  • Accepts direct caught causes and causes derived through getCause() or getTargetException().

Vibe Bot added 5 commits April 29, 2026 13:53
Tests cover checked exceptions wrapped in RuntimeException or Error while
preserving the caught cause directly, through getCause(), or through
getTargetException(). They also keep coverage for generic, unchecked,
message-only, and unrelated-cause wrappers that should still report.

Relates to SONARJAVA-6053
Do not report raw RuntimeException or Error constructors when they are used
inside a catch block to preserve a specific checked exception as the cause.
The implementation follows the approved proposal by keeping throws-clause
reporting unchanged, checking the enclosing catch type, and accepting direct
caught exceptions plus getCause/getTargetException-derived causes.

Relates to SONARJAVA-6053.
Handle checked-exception wrapper suppression when catch type semantics are
degraded, while still requiring RuntimeException/Error wrappers to preserve the
caught exception as the cause. Keep the non-compiling regression sample for an
unresolved checked exception wrapper and align the ruling analysis with the
current actual results.
Centralize raw exception type names in RawExceptionCheck so the S112
checked-exception wrapper logic no longer duplicates fully qualified class
name literals reported by java:S1192.

No suppressions were added.
@sonar-nigel
Copy link
Copy Markdown
Contributor Author

sonar-nigel Bot commented May 1, 2026

Rule Profile

Field Value
Rule S112 — Generic exceptions should never be thrown
Severity / type Major CODE_SMELL
Sonar Way Yes
Scope Main
throw new Error("internal error");

False Positive Pattern

The false positives happen when code catches a specific checked exception and converts it to an unchecked wrapper because the enclosing API cannot or should not declare that checked exception. In that pattern, the generic wrapper type is intentional and the caught exception is preserved as the cause, so consumers still have the original failure context.

try {
    return invokeAsync(prompt).get();
}
catch (InterruptedException | ExecutionException e) {
    throw new RuntimeException(e);
}

False Negative Risk

The suppression is intentionally narrow: it only applies to RuntimeException and Error constructors inside a catch block, only when all caught alternatives are specific checked exceptions, and only when a constructor argument is the caught exception or a cause derived from it through getCause() or getTargetException(). Generic Exception/Throwable catches, unchecked catches, message-only wrappers, unrelated causes, and throws clause declarations continue to be reported, so the FN risk is bounded to deliberate checked-to-unchecked wrapping patterns.

Fix Summary

The implementation adds a catch-context check before reporting constructed raw exceptions. It recognizes preserved checked causes while leaving the rule's existing broad-exception behavior intact.

  • Limits the exception to RuntimeException and Error wrappers.
  • Validates catch parameter types as specific checked exceptions, including multi-catch.
  • Supports direct caught exceptions and effectively-final locals initialized from getCause() or getTargetException().

@hashicorp-vault-sonar-prod
Copy link
Copy Markdown
Contributor

hashicorp-vault-sonar-prod Bot commented May 1, 2026

SONARJAVA-6053

@sonarqube-next
Copy link
Copy Markdown

sonarqube-next Bot commented May 4, 2026

Quality Gate failed Quality Gate failed

Failed conditions
68.6% Coverage on New Code (required ≥ 90%)

See analysis details on SonarQube

@github-actions
Copy link
Copy Markdown
Contributor

This PR is stale because it has been open 7 days with no activity. If there is no activity in the next 7 days it will be closed automatically

@github-actions github-actions Bot added the stale label May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants