openclaw - ✅(Solved) Fix [Bug]: MacNodeBrowserProxy crash on JSON serialization (2026.3.8-beta.1) [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#44600Fetched 2026-04-08 00:44:42
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
cross-referenced ×1

The OpenClaw Mac App (Node mode) crashes repeatedly with SIGABRT when processing a browser proxy invoke from the Gateway. The crash is 100% reproducible — the app crashes within ~3 seconds of launching.

Error Message

Thread 6 Crashed (com.apple.root.default-qos.cooperative):

Exception Type: EXC_CRASH (SIGABRT) Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6

Last Exception Backtrace: Foundation +[NSJSONSerialization dataWithJSONObject:options:error:] OpenClaw static MacNodeBrowserProxy.makeRequest(params:endpoint:) + 4296 OpenClaw MacNodeBrowserProxy.request(paramsJSON:) + 120 OpenClaw MacNodeRuntime.handleBrowserProxyInvoke(:) OpenClaw MacNodeRuntime.handleInvoke(:) OpenClaw closure #4 in MacNodeModeCoordinator.run() OpenClaw GatewayNodeSession.invokeWithTimeout(request:timeoutMs:onInvoke:)

Root Cause

MacNodeBrowserProxy.makeRequest(params:endpoint:) constructs a Swift Dictionary that gets bridged to NSDictionary and passed to NSJSONSerialization.dataWithJSONObject. The dictionary contains a value that is not a valid JSON type (likely nil, an unbridgeable Swift enum/struct, or a non-serializable type), causing _writeJSONValue to throw an NSInvalidArgumentException.

The exception is not caught, propagating through:

  1. _SwiftDeferredNSDictionary.enumerateKeysAndObjects — iterating dict entries
  2. _writeJSONValue — fails on invalid value
  3. objc_exception_throw__cxa_throwstd::__terminateabort()

Fix Action

Fixed

PR fix notes

PR #45895: fix(mac): guard browser.proxy JSON serialization against non-serializable values

Description (problem / solution / changelog)

Summary

  • Problem: The macOS menubar app crashes with SIGABRT when MacNodeBrowserProxy.makeRequest passes non-JSON-serializable values to NSJSONSerialization. Crash reports show __SwiftValue exceptions in the serialization path.
  • Why it matters: The app crashes and disconnects from the gateway whenever a browser.proxy request contains unexpected value types, breaking browser control for users. Four duplicate issues confirm this is actively hitting users.
  • What changed: Added sanitizeForJSON(_:) recursive sanitizer in MacNodeBrowserProxy that converts non-JSON-serializable values to String(describing:) before passing to NSJSONSerialization. Also added explicit CronJob memberwise init to fix a pre-existing Swift 6.2 build error in the test target.
  • What did NOT change: No changes to the gateway, protocol, or network layer. No changes to AnyCodable decoding — the sanitizer is purely a defensive layer at serialization time.

Change Type

  • Bug fix

Scope

  • Skills / tool execution

Linked Issue/PR

  • Closes #40957
  • Closes #42287
  • Closes #43872
  • Closes #44600

User-visible / Behavior Changes

None. The app previously crashed silently; it now gracefully sanitizes the request body.

Security Impact

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)

Evidence

  • Failing test/log before + passing after
    • Crash log: OpenClaw-2026-03-13-041109.ips (SIGABRT in MacNodeBrowserProxy.makeRequest, lastExceptionBacktrace at NSJSONSerialization dataWithJSONObject)
    • Gateway log: node.invoke returns UNAVAILABLE: Error: node disconnected (browser.proxy) at the same timestamp
  • All 7 tests pass (5 new + 2 existing):
✔ sanitizeForJSONConvertsNonSerializableValuesToStrings
✔ sanitizeForJSONRecursesIntoDictionaries
✔ sanitizeForJSONRecursesIntoArrays
✔ sanitizeForJSONPreservesJSONSafeValues
✔ postRequestWithNonSerializableBodyDoesNotCrash
✔ postRequestSerializesNestedBodyWithoutCrash (existing)
✔ request uses browser control endpoint and wraps result (existing)

Human Verification (required)

  • Verified scenarios: sanitizeForJSON with opaque Swift structs, nested dictionaries, arrays, JSON-safe primitives (String/Int/Bool/NSNull), full proxy request round-trip through mock HTTP
  • Edge cases checked: NSNull passthrough, NSNumber boolean detection via CFGetTypeID, recursive nesting through mixed dict/array structures
  • What you did not verify: Runtime behavior with the signed menubar app binary (requires full app build + signing to test with live gateway)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert commit d93287c
  • Files/config to restore: apps/macos/Sources/OpenClaw/NodeMode/MacNodeBrowserProxy.swift
  • Known bad symptoms reviewers should watch for: browser.proxy requests returning garbled body content instead of JSON

Risks and Mitigations

  • Risk: String(describing:) may produce verbose or unexpected output for complex opaque types
    • Mitigation: This is a last-resort fallback for edge cases that previously caused hard crashes. Normal JSON payloads (the common case) pass through untouched by the fast-path isValidJSONObject check.

🤖 AI-assisted. Fully tested (7/7 tests passing).

Changed files

  • apps/macos/Sources/OpenClaw/NodeMode/MacNodeBrowserProxy.swift (modified, +29/-1)
  • apps/macos/Tests/OpenClawIPCTests/MacNodeBrowserProxyTests.swift (modified, +98/-0)

Code Example

Thread 6 Crashed (com.apple.root.default-qos.cooperative):

Exception Type: EXC_CRASH (SIGABRT)
Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6

Last Exception Backtrace:
  Foundation    +[NSJSONSerialization dataWithJSONObject:options:error:]
  OpenClaw      static MacNodeBrowserProxy.makeRequest(params:endpoint:) + 4296
  OpenClaw      MacNodeBrowserProxy.request(paramsJSON:) + 120
  OpenClaw      MacNodeRuntime.handleBrowserProxyInvoke(_:)
  OpenClaw      MacNodeRuntime.handleInvoke(_:)
  OpenClaw      closure #4 in MacNodeModeCoordinator.run()
  OpenClaw      GatewayNodeSession.invokeWithTimeout(request:timeoutMs:onInvoke:)
RAW_BUFFERClick to expand / collapse

Bug Report

Version: OpenClaw Mac App 2026.3.8-beta.1 (Build 2026030801) Platform: macOS 26.3.1 (25D2128), Mac16,12 (MacBook Air M4), ARM-64 Severity: Critical — App crashes immediately on launch

Description

The OpenClaw Mac App (Node mode) crashes repeatedly with SIGABRT when processing a browser proxy invoke from the Gateway. The crash is 100% reproducible — the app crashes within ~3 seconds of launching.

Crash Stack Trace (Key Frames)

Thread 6 Crashed (com.apple.root.default-qos.cooperative):

Exception Type: EXC_CRASH (SIGABRT)
Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6

Last Exception Backtrace:
  Foundation    +[NSJSONSerialization dataWithJSONObject:options:error:]
  OpenClaw      static MacNodeBrowserProxy.makeRequest(params:endpoint:) + 4296
  OpenClaw      MacNodeBrowserProxy.request(paramsJSON:) + 120
  OpenClaw      MacNodeRuntime.handleBrowserProxyInvoke(_:)
  OpenClaw      MacNodeRuntime.handleInvoke(_:)
  OpenClaw      closure #4 in MacNodeModeCoordinator.run()
  OpenClaw      GatewayNodeSession.invokeWithTimeout(request:timeoutMs:onInvoke:)

Root Cause Analysis

MacNodeBrowserProxy.makeRequest(params:endpoint:) constructs a Swift Dictionary that gets bridged to NSDictionary and passed to NSJSONSerialization.dataWithJSONObject. The dictionary contains a value that is not a valid JSON type (likely nil, an unbridgeable Swift enum/struct, or a non-serializable type), causing _writeJSONValue to throw an NSInvalidArgumentException.

The exception is not caught, propagating through:

  1. _SwiftDeferredNSDictionary.enumerateKeysAndObjects — iterating dict entries
  2. _writeJSONValue — fails on invalid value
  3. objc_exception_throw__cxa_throwstd::__terminateabort()

Suggested Fix

Either:

  1. Validate/sanitize the params dictionary before JSON serialization (filter out nil/non-JSON values)
  2. Wrap NSJSONSerialization call in do-catch and return an error response instead of crashing
  3. Use JSONSerialization.isValidJSONObject() as a pre-check

Steps to Reproduce

  1. Install OpenClaw Mac App 2026.3.8-beta.1 on a Mac
  2. Pair with a Gateway as a Node
  3. Gateway sends a browser proxy invoke
  4. App crashes within 3 seconds of connecting

Environment

  • Hardware: MacBook Air M4 (Mac16,12)
  • OS: macOS 26.3.1 (25D2128)
  • OpenClaw: 2026.3.8-beta.1 (2026030801)
  • SIP: enabled
  • Incident ID: D0672842-527D-4E83-A3D6-E5EF9A46308E

extent analysis

Fix Plan

To resolve the crash issue, we will implement a combination of the suggested fixes:

  • Validate and sanitize the params dictionary before JSON serialization
  • Wrap the NSJSONSerialization call in a do-catch block to handle any exceptions

Here are the concrete steps:

  1. Validate and sanitize the params dictionary: Before passing the dictionary to NSJSONSerialization, filter out any nil or non-JSON values.

    func sanitizeDictionary(_ dictionary: [String: Any]) -> [String: Any] {
        var sanitizedDict = [String: Any]()
        for (key, value) in dictionary {
            if let value = value {
                sanitizedDict[key] = value
            }
        }
        return sanitizedDict
    }
  2. Wrap NSJSONSerialization call in a do-catch block: Use a do-catch block to catch any exceptions thrown by NSJSONSerialization and return an error response instead of crashing.

    func makeRequest(params: [String: Any], endpoint: String) {
        let sanitizedParams = sanitizeDictionary(params)
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: sanitizedParams, options: [])
            // Proceed with the request
        } catch {
            // Handle the error and return an error response
            print("Error serializing JSON: \(error)")
            // Return an error response or throw a custom error
        }
    }
  3. Use JSONSerialization.isValidJSONObject() as a pre-check: Before attempting to serialize the dictionary, use JSONSerialization.isValidJSONObject() to check if the object is valid.

    func makeRequest(params: [String: Any], endpoint: String) {
        let sanitizedParams = sanitizeDictionary(params)
        if JSONSerialization.isValidJSONObject(sanitizedParams) {
            do {
                let jsonData = try JSONSerialization.data(withJSONObject: sanitizedParams, options: [])
                // Proceed with the request
            } catch {
                // Handle the error and return an error response
                print("Error serializing JSON: \(error)")
                // Return an error response or throw a custom error
            }
        } else {
            // Handle the error and return an error response
            print("Invalid JSON object")
            // Return an error response or throw a custom error
        }
    }

Verification

To verify that the fix worked, follow these steps:

  • Run the app and pair it with a Gateway as a Node
  • Send a browser proxy invoke from the Gateway
  • The app should no longer crash and should handle the request correctly

Extra Tips

  • Always validate and sanitize user input data before processing it
  • Use do-catch blocks to handle exceptions and prevent crashes
  • Use JSONSerialization.isValidJSONObject() to pre-check if an object is valid before attempting to serialize it

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: MacNodeBrowserProxy crash on JSON serialization (2026.3.8-beta.1) [1 pull requests, 1 participants]