Skip to content

App killed by iOS (Jetsam / per-process-limit) when NFC tag triggers scan_tag webhook on large HA installations #4475

@cls2020

Description

@cls2020

Environment:

  • iOS App Version: 2026.2.1 (Build 2026.1766)
  • Home Assistant Server Version: 2026.3.2
  • Device: iPhone 14 (iPhone14,5)
  • iOS Version: 26.3.1 (23D771330a)

Description:
When scanning an NFC tag that triggers a scan_tag webhook, the Home Assistant iOS app is killed by iOS due to exceeding the per-process memory limit. This happens reliably and reproducibly — even when the app is fully loaded in the foreground before scanning the tag.

The issue can also be reproduced by calling the NFC scan URL handler directly (without a physical NFC tag).

Steps to Reproduce:

  1. Open the Home Assistant app and wait until it is fully loaded
  2. Scan an NFC tag configured to trigger a scan_tag webhook (or call the equivalent URL handler directly)
  3. The app is terminated by iOS immediately after the webhook is sent

Expected Behavior:

The app remains open after the NFC scan and the automation is triggered normally.

Actual Behavior:

The app is killed by iOS. The Jetsam log identifies the kill reason as per-process-limit, meaning the app exceeded its allocated memory budget.

Root Cause Analysis:

The Jetsam event log (bug_type: 298) clearly identifies the Home Assistant app as the largestProcess and shows it was killed due to per-process-limit:

"largestProcess" : "Home Assistant",
"name" : "Home Assistant",
"reason" : "per-process-limit",
"lifetimeMax" : 134272,
"pid" : 1008

With a page size of 16,384 bytes, lifetimeMax of 134,272 pages corresponds to approximately 2.05 GB of memory — the hard ceiling iOS enforces for this device class.

The app log shows that immediately after the NFC scan triggers the app, a full subscribe_entities request is initiated (WebSocket Request ID 13), loading the complete entity state for a large Home Assistant instance:

[HAAPI.swift:844] UpdateSensors > updating sensors [...]
[AppDatabaseUpdater.swift] Successfully saved 1625 entity registry entries
[AppDatabaseUpdater.swift] Successfully saved 197 device registry entries
[AppDatabaseUpdater.swift] ✅ Full update for server Home completed in 0.906s

This full entity reload — 1,625 entity registry entries and 197 device registry entries — appears to push memory consumption over the iOS limit, causing the process to be killed.

Additional context from app log:

The app log also shows a recurring error on every startup that may be related:

[AppDelegate.swift:312] checkForAlerts() > check error: 
The first or last element was requested for an empty sequence

And a WebSocket subscription inconsistency:

[Environment.swift:76] WebSocket: unable to find request for identifier HARequestIdentifier(rawValue: 6)
[Environment.swift:76] WebSocket: unable to find subscription for identifier HARequestIdentifier(rawValue: 6)

Jetsam memory state at time of kill:

"memoryStatus": {
  "compressorSize": 41704,
  "compressions": 1997039,
  "decompressions": 1258289,
  "uncompressed": 211946,
  "memoryPages": {
    "active": 62280,
    "inactive": 56799,
    "fileBacked": 46250,
    "wired": 56753,
    "anonymous": 77872,
    "free": 7043
  }
}

The system was already under memory pressure (only 7,043 free pages ≈ ~112 MB free) when the kill occurred.

Suspected fix area:

The full entity reload triggered by an NFC scan (or any URL-handler-based app activation) should either be deferred, streamed incrementally, or avoided entirely if the local database is already up to date. Triggering a complete registry refresh in response to a simple NFC scan seems disproportionate and is likely the proximate cause of the memory spike.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions