Skip to content

ValueError: buffer source array is read-only during ILP solve with pandas 2.0 #278

Description

@allysonryan

Environment

  • ultrack 0.7.2
  • Python 3.12
  • pandas 2.x
  • scikit-image 0.26.0
  • Gurobi solver (CPU node)

Error

ValueError: buffer source array is read-only

Full traceback:

File ".../ultrack/core/solve/solver/mip_solver.py", line 181, in add_edges
    sources = self._forward_map[np.asarray(sources, dtype=int)]
              ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../skimage/util/_map_array.py", line 184, in __getitem__
    out = map_array(...)
  File ".../skimage/util/_map_array.py", line 72, in map_array
    _map_array(input_arr, out_view, input_vals, output_vals)
  File "skimage/util/_remap.pyx", line 10, in skimage.util._remap._map_array
  File "<stringsource>", line 352, in View.MemoryView.memoryview.__cinit__
ValueError: buffer source array is read-only

Root cause

In pandas 2.0, the numpy arrays backing DataFrame columns are marked WRITEABLE=False to prevent accidental in-place mutation. When np.asarray(df["source_id"], dtype=int) is called and the column dtype already matches, numpy returns a read-only view of the column's backing array rather than a copy. scikit-image's _remap.pyx Cython code requires a writable buffer to construct its typed memoryview, and raises this error.

The same pattern appears in 8 places across mip_solver.py:

sources = self._forward_map[np.asarray(sources, dtype=int)]   # lines ~181, 239, 300
targets = self._forward_map[np.asarray(targets, dtype=int)]   # lines ~182, 240, 301
indices = self._forward_map[np.asarray(indices, dtype=int)]   # lines ~264, 336

Impact

The .db files (nodes + edges) are written successfully before the crash since segment() and link() complete before solve() is called. Only the ILP solve step fails, so no track assignments are produced and the pipeline cannot continue.

Fix

Add .copy() to force a writable array before passing to ArrayMap.__getitem__:

sources = self._forward_map[np.asarray(sources, dtype=int).copy()]
targets = self._forward_map[np.asarray(targets, dtype=int).copy()]
indices = self._forward_map[np.asarray(indices, dtype=int).copy()]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions