Description
Starting in Swift 6.3, values explicitly captured by exit test closures are encoded as JSON in the parent process and decoded in the child process.
Float and Double satisfy the Codable and Sendable requirements for captured values, but the default JSONEncoder rejects .infinity, -.infinity, and .nan. As a result, the exit test reports an encoding error before launching its body.
This became observable when exit-test value capturing was introduced in Swift 6.3.
Reproduction
import Testing
@Test
func captureNonFiniteFloatingPointValue() async {
let value = Double.infinity
await #expect(processExitsWith: .success) { [value = value as Double] in
precondition(value == .infinity)
}
}
Run swift test.
The test reports an error containing:
A system failure occurred: EncodingError.invalidValue:: inf(Double). Debug description: Unable to encode Double.inf directly in JSON
Expected behavior
Non-finite floating-point values should round-trip through an exit test capture list so the subprocess body can run. Positive and negative infinity should retain their sign, and NaN should remain NaN.
Environment
Swift Testing Library Version: 1902
Apple Swift version 6.3.3 effective-5.10 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)
Xcode 26.6 (17F113)
macOS 26.5.2 (25F84)
The same failure also occurs in CI on macOS 15.5 with Xcode 26.6 / Swift 6.3.3.
Additional information
Exit-test value capture was introduced by ST-0012: Exit Test Value Capturing.
A workaround is to capture each floating-point value's bitPattern as an integer and reconstruct the value in the subprocess closure, but this exposes an implementation detail to every affected test.
- await #expect(processExitsWith: .failure) { [min, ideal, max] in
+ await #expect(processExitsWith: .failure) {
+ [
+ minBitPattern = Double(min).bitPattern as UInt64,
+ idealBitPattern = Double(ideal).bitPattern as UInt64,
+ maxBitPattern = Double(max).bitPattern as UInt64,
+ ] in
+ let min = CGFloat(Double(bitPattern: minBitPattern))
+ let ideal = CGFloat(Double(bitPattern: idealBitPattern))
+ let max = CGFloat(Double(bitPattern: maxBitPattern))
Swift Open Source Slack channel discussion https://swift-open-source.slack.com/archives/C06QXFKB4ER/p1786820881281939
Description
Starting in Swift 6.3, values explicitly captured by exit test closures are encoded as JSON in the parent process and decoded in the child process.
FloatandDoublesatisfy theCodableandSendablerequirements for captured values, but the defaultJSONEncoderrejects.infinity,-.infinity, and.nan. As a result, the exit test reports an encoding error before launching its body.This became observable when exit-test value capturing was introduced in Swift 6.3.
Reproduction
Run
swift test.The test reports an error containing:
Expected behavior
Non-finite floating-point values should round-trip through an exit test capture list so the subprocess body can run. Positive and negative infinity should retain their sign, and NaN should remain NaN.
Environment
The same failure also occurs in CI on macOS 15.5 with Xcode 26.6 / Swift 6.3.3.
Additional information
Exit-test value capture was introduced by ST-0012: Exit Test Value Capturing.
A workaround is to capture each floating-point value's
bitPatternas an integer and reconstruct the value in the subprocess closure, but this exposes an implementation detail to every affected test.Swift Open Source Slack channel discussion https://swift-open-source.slack.com/archives/C06QXFKB4ER/p1786820881281939