iOS development
UITableView
debugging
software error
app development

'Invalid update invalid number of rows in section 0

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Invalid update: invalid number of rows in section 0 is a UITableView or UICollectionView consistency error. It means the UI was told to insert, delete, or reload rows in a way that does not match the data source count before and after the update.

What The Error Really Means

A table view expects this relationship to hold after a batch update:

  • new row count equals old row count plus inserts minus deletes plus moves in or out

If your data model says the section contains one number of rows but your animation calls imply another, UIKit throws this error instead of rendering an inconsistent list.

So the root problem is almost always one of these:

  • data source was not updated before the UI call
  • wrong index paths were used
  • multiple updates were applied out of sync
  • an asynchronous reload changed the count unexpectedly

Update The Model First

The most common fix is simple: mutate the backing array first, then tell the table view what changed.

swift
1var items = ["A", "B", "C"]
2
3func addItem() {
4    let newIndex = items.count
5    items.append("D")
6
7    tableView.performBatchUpdates {
8        tableView.insertRows(at: [IndexPath(row: newIndex, section: 0)], with: .automatic)
9    }
10}

This works because numberOfRowsInSection will now return the post-insert count when UIKit checks it.

Delete Example

The same ordering rule applies to deletion.

swift
1func deleteItem(at row: Int) {
2    items.remove(at: row)
3
4    tableView.performBatchUpdates {
5        tableView.deleteRows(at: [IndexPath(row: row, section: 0)], with: .automatic)
6    }
7}

If you call deleteRows before removing the element from items, the table view and the data source disagree during validation.

Reloading Everything Is Not The Same Thing

Sometimes developers mix reloadData() with fine-grained row updates in the same logical change. That can create difficult timing bugs, especially if diffing logic, fetched results controllers, or async callbacks also touch the data source.

Choose one strategy per update path:

  • full reload for simple brute-force refresh
  • precise insert, delete, move, and reload calls for animated incremental updates

Mixing both casually often creates row-count mismatches.

Data Source Contract Example

A basic data source implementation makes the contract visible.

swift
1override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2    return items.count
3}
4
5override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
6    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
7    cell.textLabel?.text = items[indexPath.row]
8    return cell
9}

Every animated update must leave items.count consistent with what UIKit expects for the section.

When Async Code Causes The Crash

This error often appears when updates arrive from a network callback, Combine publisher, or diffable data source replacement at the same time as user actions. The fix is to serialize state changes on the main thread and ensure one coherent source of truth for the section contents.

If multiple code paths can mutate the same array, the crash is often a symptom of architecture drift rather than a single bad insertRows call.

Common Pitfalls

The most common mistake is calling insertRows or deleteRows before updating the backing array.

Another mistake is calculating index paths from stale state. If the array changed earlier in the same method or callback chain, your saved row number may no longer be valid.

A third issue is mixing reloadData() with batched row animations for the same logical update. Pick one update style per change path.

Summary

  • This error means the section row count in the UI update does not match the data source.
  • Update the backing model before calling row insertion or deletion APIs.
  • Make sure index paths are calculated from current state, not stale state.
  • Avoid mixing full reloads with granular animated updates casually.
  • Treat repeated occurrences as a data-flow consistency bug, not just a table-view animation bug.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.