Once a label has been placed and saved, deleting the label (e.g., if the keypoint is not in the frame) deletes it from the napari GUI, but saving it does nothing (no "overwrite" warning). Upon reloading, the label reappears.
The previously deleted label is still there when the image is reopened in napari.
If I open the same folder/image with a previous version of napari-deeplabcut (napari-deeplabcut 0.2.1.7, via DeepLabCut 3.0.0rc13), I can use that napari-deeplabcut to delete the same label and then save it, and the label will remain deleted upon reloading the file. So the bug seems to be associated with the newer napari-deeplabcut version.
21:05:46.486 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: None
21:05:46.591 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: None
21:05:46.601 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Lifecycle manager adopting existing layers count=0
21:05:46.905 | DEBUG | napari_deeplabcut.core.io | READ_HDF file=F:\DLC_Projects\troubleshoot-tc-2026-06-02\labeled-data\A2ACr597_Pre-S1-1\CollectedData_tc.h5
21:05:46.905 | DEBUG | napari_deeplabcut.core.io | READ_HDF raw column names=['bodyparts', 'coords']
21:05:46.905 | DEBUG | napari_deeplabcut.core.io | READ_HDF raw first columns=[('body', 'x'), ('body', 'y')]
21:05:46.905 | DEBUG | napari_deeplabcut.core.io | READ_HDF header.bodyparts=['body']
21:05:46.921 | DEBUG | napari_deeplabcut.core.io | STACKED df bodyparts unique=['body']
21:05:46.921 | DEBUG | napari_deeplabcut.core.io | STACKED df individuals unique=['']
21:05:47.375 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Lifecycle manager processing insert layer='images' type=Image index=0
21:05:47.375 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Setup image layer='images' index=0 reorder=True paths_count=2 root='F:\\DLC_Projects\\troubleshoot-tc-2026-06-02\\labeled-data\\A2ACr597_Pre-S1-1' context_changed=True
21:05:47.387 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: None
21:05:47.444 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: None
21:05:47.818 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Lifecycle manager processing insert layer='CollectedData_tc' type=Points index=1
21:05:47.841 | DEBUG | napari_deeplabcut._widgets | Setup points layer='CollectedData_tc' metadata_keys=['colormap_name', 'config_colormap', 'face_color_cycles', 'header', 'io', 'kind', 'name', 'paths', 'root', 'source_h5', 'source_h5_name', 'source_h5_stem']
21:05:47.841 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Wire points layer='CollectedData_tc' existing_store=True project=None root=F:\DLC_Projects\troubleshoot-tc-2026-06-02\labeled-data\A2ACr597_Pre-S1-1 len_paths=2
21:05:47.841 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Setup points layer='CollectedData_tc' allow_merge=True metadata_keys=['colormap_name', 'config_colormap', 'face_color_cycles', 'header', 'io', 'kind', 'name', 'paths', 'root', 'source_h5', 'source_h5_name', 'source_h5_stem']
21:05:47.841 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Remap start layer='CollectedData_tc' old_paths_len=2 new_paths_len=2 data_shape=(2, 3) frame_min=0 frame_max=1
21:05:47.841 | DEBUG | napari_deeplabcut.core.remap | Remap mapping stats: depth=3 old=2 new=2 mapped=2 identity=2 overlap=2
21:05:47.841 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Remap result layer='CollectedData_tc' changed=False mapped_count=2 depth=3 message=Path keys already aligned; no remap needed. warnings=()
21:05:47.841 | DEBUG | napari_deeplabcut.core.layer_lifecycle.manager | Remap accepted-noop for CollectedData_tc (depth=3, mapped=2): Path keys already aligned; no remap needed.
21:05:47.842 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:47.933 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.934 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.934 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.936 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.939 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Trajectory plot built: layer='CollectedData_tc' df_shape=(2, 2) n_series=1 frame_bounds=(0.0, 1.0)
21:05:47.956 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Determining visible trajectory lines from points layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:47.956 | DEBUG | napari_deeplabcut.ui.color_scheme_display | Skipping unavailable Points event 'shown' for layer='CollectedData_tc'
21:05:47.980 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:47.988 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.988 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.989 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.991 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:47.993 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Trajectory plot built: layer='CollectedData_tc' df_shape=(2, 2) n_series=1 frame_bounds=(0.0, 1.0)
21:05:48.011 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Determining visible trajectory lines from points layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:48.017 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:48.024 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.024 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.025 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.027 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.029 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Trajectory plot built: layer='CollectedData_tc' df_shape=(2, 2) n_series=1 frame_bounds=(0.0, 1.0)
21:05:48.045 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Determining visible trajectory lines from points layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:48.049 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Loading trajectory plot DataFrame from layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:48.056 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.056 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.057 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.059 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:05:48.061 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Trajectory plot built: layer='CollectedData_tc' df_shape=(2, 2) n_series=1 frame_bounds=(0.0, 1.0)
21:05:48.078 | DEBUG | napari_deeplabcut.ui.plots.trajectory | Determining visible trajectory lines from points layer: <Points layer 'CollectedData_tc' at 0x1d84dbb9a30>
21:05:48.093 | DEBUG | napari_deeplabcut.ui.color_scheme_display | Updating color scheme display with 1 entries
21:06:02.902 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:02.918 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:02.918 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
21:06:02.918 | DEBUG | napari_deeplabcut._widgets | About to save. io.kind=<AnnotationKind.GT: 'gt'> save_target=None
21:06:02.923 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:02.923 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:02.923 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
21:06:02.934 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.934 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.934 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.949 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.949 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:02.949 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:02.949 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
21:06:02.987 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:02.987 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:02.987 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
21:06:02.987 | DEBUG | napari_deeplabcut.core.io | HEADER nlevels: 4
21:06:02.987 | DEBUG | napari_deeplabcut.core.io | HEADER names: ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.987 | DEBUG | napari_deeplabcut.core.io | WRITE header bodyparts=['body']
21:06:02.987 | DEBUG | napari_deeplabcut.core.io | WRITE props labels unique=['body']
21:06:02.987 | DEBUG | napari_deeplabcut.core.dataframes | Before reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.987 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.998 | DEBUG | napari_deeplabcut.core.dataframes | After reindex: cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.998 | DEBUG | napari_deeplabcut.core.dataframes | header cols nlevels 4, names ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:02.998 | DEBUG | napari_deeplabcut.core.io | DF_NEW columns nlevels: 4
21:06:02.998 | DEBUG | napari_deeplabcut.core.io | DF_NEW columns names: ['scorer', 'individuals', 'bodyparts', 'coords']
21:06:03.002 | DEBUG | napari_deeplabcut.core.io | DF_NEW finite count: 2
21:06:03.002 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:03.002 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:03.002 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
21:06:03.014 | DEBUG | napari_deeplabcut.core.io | Resolved multianimalproject=False from config at F:\DLC_Projects\troubleshoot-tc-2026-06-02\config.yaml
21:06:03.014 | DEBUG | napari_deeplabcut.core.io | FINAL WRITE first columns=[('tc', 'body', 'x'), ('tc', 'body', 'y')]
21:06:03.014 | DEBUG | napari_deeplabcut.core.io | FINAL WRITE bodyparts unique=['body']
21:06:03.014 | DEBUG | napari_deeplabcut.core.io | FINAL WRITE columns nlevels: 3
21:06:03.014 | DEBUG | napari_deeplabcut.core.io | FINAL WRITE columns names: ['scorer', 'bodyparts', 'coords']
21:06:03.045 | DEBUG | napari_deeplabcut.core.metadata | Raw header type=<class 'dict'>
21:06:03.045 | DEBUG | napari_deeplabcut.core.metadata | Raw header has columns=False
21:06:03.045 | DEBUG | napari_deeplabcut.core.metadata | columns type=<class 'NoneType'>
Pre-submission checklist
Bug summary
Once a label has been placed and saved, deleting the label (e.g., if the keypoint is not in the frame) deletes it from the napari GUI, but saving it does nothing (no "overwrite" warning). Upon reloading, the label reappears.
Steps to reproduce
Expected behavior
Actual behavior
The previously deleted label is still there when the image is reopened in napari.
Data type
Single-animal
How are you running napari?
From within the DeepLabCut GUI
Additional context
If I open the same folder/image with a previous version of napari-deeplabcut (napari-deeplabcut 0.2.1.7, via DeepLabCut 3.0.0rc13), I can use that napari-deeplabcut to delete the same label and then save it, and the label will remain deleted upon reloading the file. So the bug seems to be associated with the newer napari-deeplabcut version.
Debug log (highly recommended)
Environment
Viewer
Layers
Recent plugin logs
config.yaml