XCTFail immediately aborts the test in Xcode 26 — no retry on failure

Hi,

I’m seeing an unexpected change in how XCTFail behaves in UI tests after updating Xcode.

I use the following helper method:

`func waitForExistance(file: StaticString, line: UInt) -> Self {
    if !(element.exists || element.waitForExistence(timeout: Configuration.current.predicateTimeout)) {
        XCTFail("couldn't find element: \(element) after \(Configuration.current.predicateTimeout) seconds",
                file: file,
                line: line)
        return self
    } else {
        return self
    }
}`

In Xcode 16.4, this worked as expected: – when an element wasn’t found, XCTFail was triggered, but the test continued running, allowing my retry logic to execute.

After updating to Xcode 26.1 / 26.2 - the test now immediately aborts after XCTFail, without executing the next retry.

The logs show:

`t =   113.22s Tear Down
t =   113.22s     Terminate com.viessmann.care:81789
*** Assertion failure in -[UITests.Tests _caughtUnhandledDeveloperExceptionPermittingControlFlowInterruptions:caughtInterruptionException:whileExecutingBlock:], XCTestCase+IssueHandling.m:273
Test Case '-[UITests.Tests test_case]' failed (114.323 seconds).
Flushing outgoing messages to the IDE with timeout 600.00s
Received confirmation that IDE processed remaining outgoing messages`

It looks like XCTFail in Xcode 26 is now treated as an unhandled developer exception, which stops the test execution immediately, even when it’s called inside a helper method. This was not the case in earlier versions.

My questions:

Is this a regression in XCTest?

Or an intentional change in how XCTFail behaves in newer Xcode versions?

Should failures now be reported differently (e.g., using record(.init(type: .assertionFailure, …))) if I want to continue the test instead of aborting it?

I would like to restore the previous behavior where the failure is logged without terminating the entire test, so my retry mechanism can still run.

Has anyone else run into this after upgrading?

Thanks in advance!

If you’d like, I can also add recommended workarounds that actually work with Xcode 16.4 (e.g., replacing XCTFail with a non-terminating issue record).

I’m seeing the same behaviour and it’s causing my test repetition mode to not fire and thus it doesn’t re-run tests

So after some investigation. I found having the async setup() function caused this behaviour to prevent retries. When moving to the synchronous setup function I no longer get issue. The problem being I need to do async code in my setup...

If I move my code to the following, test repetitions now work and I see no such errors

override func setUp() {
        super.setUp()
        continueAfterFailure = false
        // setup async seems to prevent test repetitions from working      
        let exp = expectation(description: "setup")
        Task {
            try await setupWebApp(router: router)
            exp.fulfill()
        }
        wait(for: [exp], timeout: 10)
    }

This is a known issue in Xcode 26 and later.

When using XCTest in Xcode 26 and later, a test failure will cause the test runner process to terminate and relaunch before continuing to the next test if all the following conditions are met:

  • The test class is written in Swift,
  • The test’s continueAfterFailure property is set to false,
  • Either the test method is async or the async overload of setUp or tearDown is overridden, and
  • The test encounters a failure.

Under these conditions, the first issue recorded by each affected test will cause the test runner process to be terminated after its tearDown sequence finishes. A new test runner process will then be launched, and execution will continue with the next test. This applies to any XCTAssert calls which fail, all calls to XCTFail, and failures encountered by UI automation API calls.

This change was made to XCTest in order to improve reliability, since the XCTestCase.continueAfterFailure API uses Objective-C exceptions and can cause problems when used with Swift concurrency features like async/await.

However, the Test Repetition Mode setting in a test plan should still be honored but that is not working properly; that is a known issue (156723666).

Workarounds:

  • Set continueAfterFailure to true (or don't set it at all, since that's the default value) for affected tests, or
  • Avoid using async on the test method or overrides of async setUp or tearDown.
XCTFail immediately aborts the test in Xcode 26 — no retry on failure
 
 
Q