Frequent Crash on Table Content Change

One of my apps has been crashing on multiple Sequoia betas, something that never happened on prior macOS versions, and I’ve finally narrowed it down to a smaller reproducible case which I've attached to bug report #FB14473269.

The narrowed case is fairly trivial. A table containing data is filtered by typing into a text field which narrows the bound content by finding only text with matching substrings. It's a single basic view the source for which is included in its entirety below. To reproduce the crash:

  1. Compile and run
  2. Type “five” in the search text
  3. If this doesn’t immediately crash it with the first keystroke (there seems to be some kind of race condition so it may vary on different hardware configurations), delete a character at a time and repeat as necessary. Typing “one” on my system doesn’t crash the app, but deleting backwards to just “o” immediately crashes.

The backtrace is entirely within SwiftUI. This works flawlessly on Sonoma which is where I've been building and testing the app where this problem was first discovered, and it's completely unusable up through beta 5 of Sequoia.

It's hard to believe nobody else is encountering this. Any suggestions?

import SwiftUI

class Item: Identifiable {
  var id: String
  
  init(_ id: String) {
    self.id = id
  }
}

struct ContentView: View {
  @State var allItems = [ Item("One"), Item("Two"), Item("Three"), Item("Four"), Item("Five"), Item("Six"), Item("Seven"), Item("Eight"), Item("Nine"), Item("Ten") ]
  @State var filteredItems = [Item]()
  @State var selectedItems = Set<Item.ID>()
  @State var text: String = ""

  func filter() {
    if text == "" {
      filteredItems = allItems
    } else {
      filteredItems = allItems.filter {
        $0.id.localizedCaseInsensitiveContains(text)
      }
    }
  }

  var body: some View {
    VStack {
      TextField("Search:", text: $text)
        .padding()
        .onChange(of: text) {
          filter()
        }
        .onAppear {
          filter()
        }
      Table($filteredItems, selection: $selectedItems) {
        TableColumn("Name") { item in
          Text(item.id)
        }
      }
    }
  }
}

#Preview {
    ContentView()
}
Answered by DTS Engineer in 799816022

@KateS I wasn't able to reproduce the issue using the Latest beta. Could you test and verify using the latest beta build.

Also I would suggest you use the searchable modifier instead.

Here are a few resources to help you get started:

struct ContentView: View {
    @State private var allItems = [ Item("One"), Item("Two"), Item("Three"), Item("Four"), Item("Five"), Item("Six"), Item("Seven"), Item("Eight"), Item("Nine"), Item("Ten") ]
    @State private var filteredItems = [Item]()
    @State private var selectedItems = Set<Item.ID>()
    @State private var searchText: String = ""
    
    func filter() {
        if searchText == "" {
            filteredItems = allItems
        } else {
            filteredItems = allItems.filter {
                $0.id.localizedCaseInsensitiveContains(searchText)
            }
        }
    }
    
    var body: some View {
        NavigationStack {
            Table($filteredItems, selection: $selectedItems) {
                TableColumn("Name") { item in
                    Text(item.id)
                }
            }
        }
        .onChange(of: searchText, initial: true) { _,_  in
            filter()
        }
        .searchable(text: $searchText, placement: .sidebar)
    }
}

@KateS I wasn't able to reproduce the issue using the Latest beta. Could you test and verify using the latest beta build.

Also I would suggest you use the searchable modifier instead.

Here are a few resources to help you get started:

struct ContentView: View {
    @State private var allItems = [ Item("One"), Item("Two"), Item("Three"), Item("Four"), Item("Five"), Item("Six"), Item("Seven"), Item("Eight"), Item("Nine"), Item("Ten") ]
    @State private var filteredItems = [Item]()
    @State private var selectedItems = Set<Item.ID>()
    @State private var searchText: String = ""
    
    func filter() {
        if searchText == "" {
            filteredItems = allItems
        } else {
            filteredItems = allItems.filter {
                $0.id.localizedCaseInsensitiveContains(searchText)
            }
        }
    }
    
    var body: some View {
        NavigationStack {
            Table($filteredItems, selection: $selectedItems) {
                TableColumn("Name") { item in
                    Text(item.id)
                }
            }
        }
        .onChange(of: searchText, initial: true) { _,_  in
            filter()
        }
        .searchable(text: $searchText, placement: .sidebar)
    }
}

I'm using macOS 15.0 (24A5320a) installed this week to make sure it still reproduced. It results in the same crash under exactly the same circumstances.

I've tried a clean build using two Xcode betas, this week's Xcode 16.1 beta (16B5001e) and Xcode Version 16.0 beta 4 (16A5211f) where I originally built the reproduction case for submission. It crashes identically on both, as does the TestFlight installed app where I first discovered the problem, built using Xcode 15.4. The actual app uses the searchable modifier, which I eliminated from the repro case to try to narrow the possible sources of problems.

Did you try building the project attached to the bug report referenced above? Or something new built around the code fragment in my first message? In case it matters for reasons that aren't immediately obvious, I'm running on a base M3 Max MacBook Pro 14".

@KateS I was able to reproduce the crash you described thanks.

The crash occurs because they are duplicate items in filteredItems collection whose ID are the same.

First, I would suggest you use a unique ID for Item and use a Set for filteredItems instead of an array to ensure that they are no duplicate element.

struct Item: Identifiable, Hashable {
    var id: UUID = UUID()
    var value: String
    
    init(_ value: String) {
        self.value = value
    }
}

@State var selectedItems = Set<Item.ID>()

I'm glad to hear it's reproducing for you, and understand your theory about duplicate IDs. The actual app where this was originally detected uses UUIDs extensively, but it certainly doesn't hurt to use the same strategy in the reduced test case as well.

In the code below, not only are Item instances created with UUIDs rather than relying on string uniqueness, but every time the filter is invoked it generates new UUIDs for each item to ensure that there's not even overlap between the prior and new data sets. I still get the same crash. Table data is inherently ordered, so a Set is neither appropriate nor well-suited to SwiftUI's binding in this instance.

import SwiftUI

struct Item: Identifiable, Hashable {
  let id = UUID()
  let name: String

  init(_ name: String) {
    self.name = name
  }
}

struct ContentView: View {
  let allItems = [ Item("One"), Item("Two"), Item("Three"), Item("Four"), Item("Five"), Item("Six"), Item("Seven"), Item("Eight"), Item("Nine"), Item("Ten") ]
  @State var filteredItems = [Item]()
  @State var text: String = ""

  func filter() {
    let subset = if text == "" {
      allItems
    } else {
      allItems.filter {
        $0.name.localizedCaseInsensitiveContains(text)
      }
    }
    // To guarantee that there are no duplicate IDs, generate new
    // Item instances for the filtered set
    filteredItems = subset.map { item in
      Item(item.name)
    }
  }

  var body: some View {
    VStack {
      TextField("Search:", text: $text)
        .padding()
        .onChange(of: text) {
          filter()
        }
        .onAppear {
          filter()
        }
      Table($filteredItems) {
        TableColumn("Name") { item in
          Text(item.wrappedValue.name)
        }
      }
    }
  }
}

Sadly, Sequoia shipped with this bug. It's a lousy place to be in that prevents shipping an application that has been in beta for months – not to mention all the other SwiftUI applications that may be affected, and I can't help but feel it could have been avoided.

Please escalate the specific example to see what could have been handled differently. I've never received any acknowledgement that this bug actually exists through normal channels, only a series of replies that claim that it doesn't reproduce (it does) and that my code is incorrect (it isn't.)

So I eventually had to sidestep this whole process to make sure people took it seriously and that something was being done about it. I understand that the bug has finally been fixed and look forward to a 15.1 beta where I can confirm it. In the meantime, I'll have to sit on a finished app that works fine on Sonoma to avoid customers being burned by Sequoia.

This appears to have finally been addressed in 15.1 beta 4. Is there any chance this particular fix will be back-ported to a 15.0.x release? Of course the urgency depends entirely on the timeframe for 15.1. Just a thought.

I can confirm the bug related to SwiftUI table. It crashes somewhere in Metal framework:

-[MTLDebugRenderCommandEncoder setRenderPipelineState:]:1616: failed assertion `Set Render Pipeline State Validation
For color attachment 0, the texture sample count (1) does not match the renderPipelineState sampleCount (1065353216).

1065353216 is the binary for 1.0 float, so we can guess what the problem is.

The bad news is that 15.1 beta 4 (24B5046f) doesn't fix this for my Intel Mac.

The good news is that it works in release builds, so obviously the bug is in Metal debugger. I was able to bypass the crash by disabling Metal API validation in the app's build scheme.

Frequent Crash on Table Content Change
 
 
Q