Visitar URL original
fix(#7461): IMPORT DATABASE reported result=OK for the one failure it means to report as FAIL by robfrank · Pull Request #7493 · ArcadeData/arcadedb · GitHub
Skip to content

fix(#7461): IMPORT DATABASE reported result=OK for the one failure it means to report as FAIL - #7493

Closed
robfrank wants to merge 3 commits into
mainfrom
fix/7461-import-database-result-ok-on-fail
Closed

robfrank wants to merge 3 commits into
mainfrom
fix/7461-import-database-result-ok-on-fail

Conversation

@robfrank

@robfrank robfrank commented Sep 11, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #7461

ImportDatabaseStatement.executeSimple wrote result=FAIL in the InvocationTargetException handler and then assigned result=OK unconditionally two lines below the enclosing try, so the FAIL branch could not be observed by any caller: an IMPORT DATABASE that never ran answered {"result":"OK"} with no rows and no statistics. The branch arrived with probeOnly (#1401) and has been dead since the day it was written - Importer.load() converts a failed probe into an IllegalArgumentException precisely so this statement can report it as a row rather than by throwing, which is why this PR takes the issue's first option (keep the in-band shape, make FAIL survive, add a reason) rather than the second: throwing a CommandExecutionException would leave no way to ask "can this source be parsed?" at all. Three changes - result=OK moves into the success path immediately after the statistics are folded in (the shape BackupDatabaseStatement already has, so there is no flag and no second assignment); a reason property travels with FAIL, because FAIL on its own tells a caller nothing it can act on and the server log was the only place the message existed; and e.getTargetException() is hoisted into a null-guarded local, since e.getCause() was being dereferenced unchecked and the two accessors were mixed for the same object. The exact class-name comparison is deliberately kept rather than widened to an instanceof: the IllegalArgumentException subclasses that reach here (NumberFormatException, from ImporterSettings.parseParameter's Integer.parseInt on a numeric setting) have always been thrown, and widening the branch would silently turn those errors into rows.

The completeness sweep found a second producer of the branch that the issue does not name: setSettings reaches ImporterSettings.parseParameter, which raises the same exact type for a WITH ... value it refuses - before the import runs at all - so IMPORT DATABASE ... WITH onRowError = 'bogus' also answered OK for an import that never happened. Both producers are covered and both now carry a reason.

Test plan

New integration/src/test/java/com/arcadedb/integration/importer/Issue7461ImportDatabaseFailResultTest.java, six tests, each driving the statement through database.command("sql", ...) - the same live path a client uses:

  • aFailedProbeReportsFailWithAReason - WITH probeOnly = true on a missing source returns FAIL, with a reason naming both the failure type and the file.
  • aSuccessfulProbeStillReportsOk - a good source still returns OK, and the schema is untouched, which is what proves the probe actually probed rather than imported.
  • anUnusableSettingValueReportsFailWithAReason - WITH onRowError = 'bogus' returns FAIL with the parser's own sentence, and nothing was loaded.
  • aSuccessfulImportStillReportsOk - a plain import is unchanged: OK, statistics, 2 records, no reason.
  • aGenuineImportFailureStillThrows - a non-probe import of a missing source still throws CommandExecutionException, pinned by root cause so it cannot pass via an earlier guard.
  • aNonNumericNumericSettingStillThrows - WITH commitEvery = 'abc' still throws, root cause NumberFormatException; this is the test that fails if someone widens the match to an instanceof.

Before the fix: Tests run: 6, Failures: 2 - exactly the two FAIL rows, with the four guard tests already green. After: Tests run: 6, Failures: 0.

  • integration module, full suite minus the benchmark/slow/vector lanes: 372 tests, 0 failures, 9 skipped.
  • engine module, same lanes: 14870 tests, 1 failure - MultiColumnAggregationResultTest.emptySumAndCountStayZeroNotNaN (expected: 0.0 but was: NaN). Pre-existing on main and unrelated: re-run with ImportDatabaseStatement.java restored to its HEAD content it fails identically. Time-series aggregation, nothing to do with this change - flagging it because it is red on the base commit.
  • Server ITs that exercise the import path (ImportDatabaseSecurityIT, Issue7443SqlMaintenanceSlotIT) were not run locally: port 2480 was already held by another process on this machine, and a server IT against an occupied port reports authentication errors rather than anything meaningful. CI covers them. The SecurityException rethrow they exercise is unchanged in semantics - the loop reads the same object through a local.

Coverage

Entry point Covered by fix? Covered by a test?
WITH probeOnly = true, unparseable source -> Importer.load() raises IllegalArgumentException yes yes
WITH probeOnly = true, good source -> load() returns null yes (still OK) yes
WITH onRowError = 'bogus' -> setSettings raises the exact IllegalArgumentException yes yes
Non-probe import of an unparseable source argued - load() wraps it in ImportException, which never reached the FAIL branch and still throws yes, as a regression guard
WITH commitEvery = 'abc' -> NumberFormatException argued - the exact class-name match excludes subclasses, so this always threw and still does yes, as a regression guard
Importer raises SecurityException (SSRF/LFI guard) argued - the rethrow loop is unchanged apart from hoisting getTargetException() into a local existing ImportDatabaseSecurityIT
BACKUP / EXPORT DATABASE siblings argued - neither has an in-band FAIL; EXPORT's catch always throws, BACKUP sets OK inside its success branch. grep '"FAIL"' over the tree returns this one site n/a
Server import database <name> <url> (HTTP/gRPC/Studio button) argued - routes through ServerControlPlane.importDatabase, which drives Importer directly and never reaches this statement n/a

Known gaps

  • Startup 'import:' default-database command discards the statement's result row, so a failed import is silent #7484 - ArcadeDBServer.loadDefaultDatabases runs the import: startup command through this statement and discards the result set (// drain not needed), so a FAIL row is as silent after this fix as it was before it. This PR gives that path an answer worth reading; reading it is a server-module change. Filed before this PR opened.
  • The asymmetry between WITH commitEvery = 'abc' (throws) and WITH onRowError = 'bogus' (returns a FAIL row) is inherited, documented in the code comment, and pinned by two tests. Unifying it means deciding whether a refused setting is an error or a row for every setting - a contract change this PR deliberately does not make.

Tracking doc: docs/7461-import-database-result-ok-on-fail.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY

Summary by CodeRabbit

  • Bug Fixes
    • IMPORT DATABASE now correctly reports FAIL instead of incorrectly marking failed operations as successful.
    • Failure results include a clear reason for invalid settings and probe failures.
    • Successful imports and probes continue to report OK.
    • Genuine import and parsing errors continue to be surfaced as exceptions.
  • Documentation
    • Added documentation covering the issue, behavior, verification, and known limitations.
  • Tests
    • Added coverage for successful operations, failure results, failure reasons, and preserved exception behavior.

… means to report as FAIL

ImportDatabaseStatement.executeSimple wrote result=FAIL in the InvocationTargetException handler
and then assigned result=OK unconditionally two lines below the enclosing try, so the FAIL branch
was unobservable by any caller: an import that never ran answered {"result":"OK"} with no rows and
no statistics.

The branch arrived with probeOnly (#1401). A probe asks whether a source can be parsed, and
Importer.load() converts a failed probe into an IllegalArgumentException precisely so the statement
can report it as a row rather than by throwing - which is why this keeps the in-band shape rather
than switching to CommandExecutionException: throwing would leave no way to ask the question.

- result=OK moves into the success path, right after the statistics are folded in, the shape
  BackupDatabaseStatement already has. No flag, no second assignment.
- A reason property travels with FAIL. FAIL alone says nothing a caller can act on, and the server
  log was the only place the message existed.
- e.getTargetException() is hoisted into a local and null-guarded; e.getCause() was dereferenced
  unchecked and the two accessors were mixed for the same object.

The exact class-name comparison is deliberately kept rather than widened to an instanceof: the
IllegalArgumentException subclasses that reach here (NumberFormatException, from
ImporterSettings.parseParameter's Integer.parseInt on a numeric setting) have always been thrown,
and widening would turn those errors into rows.

The sweep found a second producer of the branch that the issue does not name:
ImporterSettings.parseParameter raises the same exact type for a WITH value it refuses, before the
import runs at all, so 'WITH onRowError = bogus' also answered OK for an import that never
happened. Both producers are covered.

Six regression tests in the integration module drive the statement through database.command("sql",
...): failed probe, successful probe, refused setting, successful import, non-probe import failure,
and the NumberFormatException subclass that must keep throwing.

Follow-up filed: #7484 - the startup 'import:' default-database command discards this result row,
so a FAIL is as silent there after this fix as before it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
@coderabbitai

coderabbitai Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 8c635a95-3459-4a59-ac26-e5ce3f8cdf12

📥 Commits

Reviewing files that changed from the base of the PR and between bfd2f18 and a2e694a.

📒 Files selected for processing (1)
  • docs/7461-import-database-result-ok-on-fail.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/7461-import-database-result-ok-on-fail.md

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

IMPORT DATABASE now preserves in-band FAIL results with failure reasons, assigns OK only after successful loading, and keeps other importer exceptions as errors. Integration tests cover failed probes, invalid settings, successful imports, and exception propagation.

Changes

IMPORT DATABASE result handling

Layer / File(s) Summary
Failure result handling
engine/src/main/java/com/arcadedb/query/sql/parser/ImportDatabaseStatement.java
The statement assigns OK only after successful loading. Targeted IllegalArgumentException failures return FAIL with a reason. Security and other exceptions retain error propagation.
Regression coverage and implementation record
integration/src/test/java/com/arcadedb/integration/importer/Issue7461ImportDatabaseFailResultTest.java, docs/7461-import-database-result-ok-on-fail.md
Integration tests cover failed probes, invalid settings, successful imports, and exception propagation. The issue record documents the implementation and verification results.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to a2e69

The change preserves failed import results and regression coverage passed; no current merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 2 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: preserving the IMPORT DATABASE FAIL result instead of reporting OK.
Description check ✅ Passed The description is detailed and covers the change, motivation, related issue, test plan, coverage, known gaps, and CI results. It does not use the template headings exactly, and it does not explicitly…
Linked Issues check ✅ Passed Issue #7461 requires the in-band failure to remain observable or the statement to throw. ImportDatabaseStatement.executeSimple now sets result=OK only in the success path. The exact `IllegalArgume…
Out of Scope Changes check ✅ Passed The production change, six integration tests, and docs/7461-import-database-result-ok-on-fail.md all support Issue #7461. The documentation records the defect, selected behavior, test coverage, and …
Full details: Docstring Coverage

Explanation

Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 2 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/7461-import-database-result-ok-on-fail

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mergify

mergify Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@codacy-production

codacy-production Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 4 complexity

Metric Results
Complexity 4

View in Codacy

🟢 Coverage ∅ diff coverage · -6.38% coverage variation

Metric Results
Coverage variation ✅ -6.38% coverage variation
Diff coverage ✅ ∅ diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (d3d9a48) 178988 147639 82.49%
Head commit (a2e694a) 211391 (+32403) 160871 (+13232) 76.10% (-6.38%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#7493) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@claude

claude Bot commented Sep 11, 2026

Copy link
Copy Markdown

Review

I traced the fix against Importer.java, SourceDiscovery.java, and ImporterSettings.java to verify the PR's claims rather than take them at face value, and they hold up.

Correctness

  • The root-cause fix is right: result=OK now only gets set right after setPropertiesFromMap(statistics) inside the success path, so it can no longer clobber a FAIL written in the InvocationTargetException handler. Matches the shape BackupDatabaseStatement already uses.
  • Importer.load() really does throw new IllegalArgumentException(e) when probeOnly is set (line 98), and ImporterSettings.parseParameter really does throw the same exact type for a refused onRowError value (line 191) - confirming both producers named in the PR description, not just the one the linked issue calls out.
  • openLocalStream (SourceDiscovery.java:216) does throw a bare-path FileNotFoundException, and IllegalArgumentException(Throwable)'s message is cause.toString(), so failureReason()'s choice to read the wrapper's own message (not the cause's) is correct and is exactly what the new test asserts (aFailedProbeReportsFailWithAReason).
  • Hoisting e.getTargetException() into a null-guarded target local is a genuine (if narrow) latent-bug fix on top of the refactor: the old code called e.getCause().getClass() unguarded, which would NPE instead of falling through to the security-exception path if getCause() ever returned null. Low real-world likelihood since InvocationTargetException always sets its target, but the guard is free and correct.
  • Keeping the exact class-name comparison instead of instanceof is well-justified and pinned by aNonNumericNumericSettingStillThrows, so a future "helpful" widening to instanceof will fail loudly instead of silently swallowing NumberFormatException (and other subclasses) into rows.

Tests

  • Good coverage: both FAIL producers, the still-throws paths (genuine import failure, non-numeric setting), and a plain successful import for regression safety. Uses AssertJ assertThat consistent with the project's testing conventions.
  • aSuccessfulProbeStillReportsOk and anUnusableSettingValueReportsFailWithAReason both assert on db.getSchema().existsType("Document") to prove the import didn't actually run, not just that the status code looks right - that's the kind of check that catches a fix which happens to return the right string for the wrong reason.
  • Reasonable to skip the two server ITs locally given the port-2480 conflict, but worth confirming they're actually green in CI before merge since the PR didn't observe them directly.

Nits (non-blocking)

  • reason is a new property key with no precedent elsewhere in the tree (setProperty("reason" has exactly one hit, the new one). Not a problem for this PR, but if a future statement wants to report similar in-band failure detail, it'd be worth keeping the key name consistent with whatever this establishes.
  • The in-code comment blocks are quite long (multi-paragraph, all-caps headers) - consistent with the rest of this file's existing style, so not something to change here, but worth keeping in mind that this file is trending toward comment-heavy for future edits.

Out of scope, correctly deferred

Overall this is a well-scoped, well-verified fix. No security or performance concerns - the SSRF/LFI guard's rethrow loop is unchanged in semantics, and no new dependencies were introduced.

Adds the PR link, the adversarial pass with its four findings and their dispositions, the cycle-1
review outcome, and the CI analysis: the branch's own six tests pass in CI, while the two red lanes
are inherited rather than caused here - three deterministic unit-test failures reproduced on an
unrelated PR (#7495) and a hardcoded-port gRPC IT collision that picks a different victim each run
(#7496).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
@robfrank

Copy link
Copy Markdown
Collaborator Author

CI: the branch's own tests pass; both red lanes are inherited

Posting the analysis so nobody has to redo it. The new test ran in CI and passed - run 34657385125's unit-test-reports artifact carries TEST-com.arcadedb.integration.importer.Issue7461ImportDatabaseFailResultTest.xml with tests="6" errors="0" skipped="0" failures="0".

unit-tests - three failures, pre-existing on the base branch. Filed as #7495.

Test Assertion
MultiColumnAggregationResultTest.emptySumAndCountStayZeroNotNaN expected: 0.0 but was: NaN
Issue7089NaNTransparentSumAvgTest.oneNaNSampleNoLongerPoisonsTheBucketOnAnyPath expected: 0 but was: 2
ArcadeStateMachinePerDatabaseHaltTest (both methods) got Corrupted WAL transaction entry, expected per-database snapshot resync in progress / Apply error on database 'db-B'

Evidence rather than inference: the unrelated PR #7489 (RDF importer only, run 34657353357) fails on exactly the same three report files, and locally MultiColumnAggregationResultTest fails identically with ImportDatabaseStatement.java restored to its HEAD content. Neither branch touches time series or Raft. main never runs this workflow, so a regression merged there first appears on somebody else's PR.

integration-tests - one failure, a hardcoded-port collision. Filed as #7496.

Issue7304GrpcAdminLeaderRoutingIT errored in @BeforeEach for both methods, before any test code ran: Failed to bind to address 0.0.0.0/0.0.0.0:51142 ... Address already in use. That class hardcodes BASE_GRPC_PORT = 51141, so 51142 is its own node 1. The same lane fails on unrelated PRs with a different victim each run (PR #7491, run 34656829906: Issue6070GraphBatchLoadLeaderGuardIT, TimeSeriesGrpcForwardedInsertTypeIT, ServerProfilingIT).

I did not re-run either lane to chase green: the three unit-test failures are deterministic on the base, and the gRPC one would only be another roll of the same dice.

@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review

Solid, well-scoped fix. result=OK was indeed unconditionally overwriting result=FAIL in ImportDatabaseStatement.executeSimple (engine/src/main/java/com/arcadedb/query/sql/parser/ImportDatabaseStatement.java), and moving the OK assignment into the success path immediately after setPropertiesFromMap is the right shape - it matches BackupDatabaseStatement and removes the dead branch entirely rather than patching around it.

Correctness

  • Confirmed there's no key collision: ImporterContext.toMap() never emits result or reason, so folding statistics in before setting result/reason is safe.
  • Confirmed via grep -rn 'getProperty("result")' that no production code branches on this property today, so making FAIL observable can't silently change existing caller behavior.
  • Hoisting e.getTargetException() into a null-guarded target local is a genuine (if minor) improvement - e.getCause() was being dereferenced unchecked right next to a separate e.getTargetException() call on the same underlying value.
  • Keeping the exact-class-name comparison ("IllegalArgumentException".equals(target.getClass().getSimpleName())) instead of instanceof is the right call given NumberFormatException reaches the same catch block from ImporterSettings.parseParameter - widening it would silently swallow those as rows instead of throwing. Good catch that this needed a dedicated regression test (aNonNumericNumericSettingStillThrows) rather than just a comment.
  • failureReason() correctly prefers the wrapper exception's own message over the cause's - important because Importer.load() builds the probe failure as new IllegalArgumentException(cause), whose message already includes the cause's toString() (type + text), while the cause itself (e.g. FileNotFoundException) often carries only a bare path.

Test coverage
Good coverage of both producers of the branch (probeOnly failure and the setSettings/onRowError failure), plus regression tests pinning that NumberFormatException and non-probe ImportException failures still throw rather than becoming rows. The tests assert on root-cause type in addition to message text, which avoids false positives from an unrelated guard that happens to produce the same top-level exception type.

Minor/non-blocking notes

  • reason is a new property with no precedent elsewhere in the result-row shape used by BackupDatabaseStatement/ExportDatabaseStatement. Not a problem for this PR, but worth keeping in mind if a future statement wants the same "FAIL + reason" shape - might be worth extracting a small convention/helper at that point rather than re-deriving it.
  • The known residual asymmetry - onRowError = 'bogus' returns a FAIL row while commitEvery = 'abc' throws - is inherited behavior, correctly called out in the code comment, and each side is pinned by its own test, so this isn't something this PR needs to fix.
  • The startup import: default-database path still discards the result set entirely (filed as Startup 'import:' default-database command discards the statement's result row, so a failed import is silent #7484), so this fix doesn't yet help that caller. That's fine as a documented out-of-scope gap rather than a silent one.

Security: The SSRF/LFI guard rethrow loop (for (Throwable cause = target; ...) if (cause instanceof SecurityException se) throw se;) is unchanged in semantics, just reading through the new local - still short-circuits ahead of the FAIL branch, so a security violation still surfaces as an exception (mapping to HTTP 403) rather than being swallowed into a row.

Performance: No concerns - this is exception-handling/result-shaping code on an already-slow-path (import), not a hot path.

Nothing blocking. Nice, tightly scoped fix with a strong regression suite.

Cycle 2 was triggered by the tracking-doc commit itself and closed with "Nothing blocking", so the
final state is clean-approval after 2 cycles. Last cycle recorded: a further doc commit would only
re-trigger a review of itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review

Went through the diff (ImportDatabaseStatement.java, the new Issue7461ImportDatabaseFailResultTest, and the tracking doc) plus traced the two producers (Importer.load() and ImporterSettings.parseParameter) against SourceDiscovery/ImporterSettings to confirm the claims in the PR body rather than take them at face value.

Correctness

  • The core fix is right: moving result.setProperty("result", "OK") into the try block immediately after setPropertiesFromMap(statistics), and removing the unconditional assignment below the outer try, is exactly what makes the FAIL branch observable again. Confirmed the previous code truly discarded it (the unconditional result.setProperty("result", "OK") at the old bottom ran regardless of which catch fired).
  • Verified independently (not just via the PR's grep) that ImporterSettings.parseParameter throws a bare IllegalArgumentException for onRowError and Integer.parseInt(value) (→ NumberFormatException, a subclass) for commitEvery — so the "second producer" claim and the "must stay exact class-name match, not instanceof" reasoning both hold up.
  • Confirmed ImporterContext.toMap() emits no result/reason key, so folding statistics in before the outcome can't collide with the new reason property.
  • failureReason() reading failure.getMessage() (not the cause's) is correct given Importer.load() builds the probe failure as new IllegalArgumentException(cause), whose message is already cause.toString().
  • Hoisting e.getTargetException() into a null-checked target local fixes a real (if narrow) unchecked-getCause() bug and is behaviorally a no-op for the SecurityException rethrow loop.

Minor / non-blocking

  • "IllegalArgumentException".equals(target.getClass().getSimpleName()) is pre-existing (not introduced here) but it's comparing a simple name string rather than target.getClass() == IllegalArgumentException.class. Since you're already touching this line, an exact-class comparison would express the same "no subclasses" intent slightly more robustly and a bit cheaper — not blocking, just noting it since the surrounding lines were rewritten anyway.
  • The reason property is new and has no precedent elsewhere in the tree (already flagged as a non-blocking note in the tracking doc's own review cycles) — worth keeping in mind if a future statement wants the same in-band-failure shape, so the key name/convention doesn't drift.

Tests

Good coverage and good discipline: each test pins more than just the result string (root-cause exception type, schema untouched to prove a probe didn't actually import, reason text on both halves) which rules out the classic "green for the wrong reason" failure mode. The two regression guards (aGenuineImportFailureStillThrows, aNonNumericNumericSettingStillThrows) are exactly the tests that would catch a future attempt to widen the instanceof/class check. I was not able to execute mvn in this review sandbox to re-run the suite myself, so I'm relying on the PR's reported local run (6/6 passing) and the CI artifact reference for Issue7461ImportDatabaseFailResultTest; the logic traces correctly by inspection.

Security / performance

No concerns. The reason string surfaces to the same caller who supplied the URL/settings that caused the failure, so there's no new information disclosure beyond what that caller already controls. No hot-path or allocation changes — this is exception-handling logic only.

Docs

The docs/7461-*.md tracking file is consistent with the existing convention in this repo (docs/69xx-*.md, docs/72xx-*.md, etc.), so no concern there.

Nice, tightly-scoped fix with a clear invariant and tests that actually pin the behavior rather than just the happy path. Nothing blocking from my pass.

@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.01%. Comparing base (d3d9a48) to head (a2e694a).
⚠️ Report is 20 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7493   +/-   ##
=======================================
  Coverage   74.00%   74.01%           
=======================================
  Files        1957     1957           
  Lines      178988   178988           
  Branches    37784    37784           
=======================================
+ Hits       132469   132476    +7     
+ Misses      31386    31385    -1     
+ Partials    15133    15127    -6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@robfrank

Copy link
Copy Markdown
Collaborator Author

Superseded by #7497, which implemented all five issues (#7341, #7342, #7345, #7347, #7461) independently and merged first, and by #7498, which carries the four follow-ups this branch only filed (#7487, #7488, #7490, #7494). Main is ahead of this branch, so merging it would regress that work.

Closing rather than resolving the conflicts. The regression tests on this branch are NOT superseded - they cover considerably more than what landed - and porting them onto the merged implementation's API is tracked separately.

@robfrank robfrank closed this Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IMPORT DATABASE reports result=OK for the one failure it means to report as FAIL

1 participant