From 3f543ba12f06a4184617b5a6cc501f4fae904bc4 Mon Sep 17 00:00:00 2001 From: Kathryn Baldauf Date: Mon, 20 Jul 2026 15:14:05 -0700 Subject: [PATCH] Remove force unwraps on XPC error set/get (#1958) Signed-off-by: Kathryn Baldauf --- Sources/ContainerXPC/XPCMessage.swift | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Sources/ContainerXPC/XPCMessage.swift b/Sources/ContainerXPC/XPCMessage.swift index 3c6a3dca..61296328 100644 --- a/Sources/ContainerXPC/XPCMessage.swift +++ b/Sources/ContainerXPC/XPCMessage.swift @@ -78,23 +78,36 @@ extension XPCMessage { public func error() throws { let data = data(key: Self.errorKey) if let data { - let item = try? JSONDecoder().decode(ContainerXPCError.self, from: data) - precondition(item != nil, "expected to receive a ContainerXPCXPCError") + guard let item = try? JSONDecoder().decode(ContainerXPCError.self, from: data) else { + throw ContainerizationError( + .internalError, + message: "received a malformed error payload from the XPC peer" + ) + } - throw ContainerizationError(item!.code, message: item!.message) + throw ContainerizationError(item.code, message: item.message) } } + /// Fallback error if `JSONEncoder` fails to encode the original error. In practice this should + /// never get used. + private static let fallbackErrorData = Data( + #"{"code":"\#(ContainerizationError.Code.internalError.description)","message":"the daemon failed to encode the original error"}"# + .utf8 + ) + public func set(error: ContainerizationError) { var message = error.message if let cause = error.cause { message += " (cause: \"\(cause)\")" } let serializableError = ContainerXPCError(code: error.code.description, message: message) - let data = try? JSONEncoder().encode(serializableError) - precondition(data != nil) + guard let data = try? JSONEncoder().encode(serializableError) else { + set(key: Self.errorKey, value: Self.fallbackErrorData) + return + } - set(key: Self.errorKey, value: data!) + set(key: Self.errorKey, value: data) } }