Skip to content

macOS: SIGABRT when requestAuthorization returns an error — raw NSError passed as FlutterError details (Pigeon codec assertion) #96

Description

@asole-olyx

Summary

On macOS, if UNUserNotificationCenter.requestAuthorization completes with a non-nil error, the app crashes with SIGABRT (uncaught NSExceptionabort()). This happens in production for regular users — e.g. after toggling the app's notification permission in System Settings and then triggering Push.instance.requestPermission().

Root cause

PushHostHandlers.requestPermissionBadge (darwin/Classes/PushHostHandlers.swift) passes the raw Error object as the details of the FlutterError:

guard error == nil else {
    completion(
        nil,
        FlutterError(
            code: "requestPermission", message: error.debugDescription, details: error
        )
    )
    return
}

Pigeon's standard message codec cannot encode an NSError. -[PUPushApiPigeonCodecWriter writeValue:] hits the NSAssertionHandler failure inside FlutterStandardWriter, the exception is thrown on the com.apple.usernotifications.UNUserNotificationServiceConnection.call-out dispatch queue where nothing catches it, and the process aborts. The Dart-side caller never gets the error — the app just dies.

Crash (excerpt, push 3.3.3, macOS 26.6)

Triggered by Thread 10, Dispatch Queue: com.apple.usernotifications.UNUserNotificationServiceConnection.call-out
Exception Type: EXC_CRASH (SIGABRT)

10  Foundation   -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 272
11  FlutterMacOS ...
13  push         -[PUPushApiPigeonCodecWriter writeValue:] + 556
...
19  push         __SetUpPUPushHostApiWithSuffix_block_invoke_5 + 56
20  push         closure #1 in PushHostHandlers.requestPermissionBadge(...) + 488

Reproduction

  1. macOS app using push 3.3.3.
  2. Get the app's notification permission into a state where requestAuthorization errors (e.g. deny, then toggle the app's notifications in System Settings while the app is running).
  3. Call Push.instance.requestPermission() → SIGABRT.

Fix

Serialize something the codec can encode — one line:

FlutterError(
    code: "requestPermission", message: error.debugDescription, details: nil
)

(or details: String(describing: error)). Then the error reaches Dart as a normal PlatformException and apps can handle it. Happy to send a PR if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions