diff --git a/src/vte.c b/src/vte.c
index 28536d5..26143e9 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -2927,11 +2927,19 @@ _vte_terminal_cleanup_fragments(VteTerminal *terminal,
                                 long start, long end)
 {
         VteRowData *row = _vte_terminal_ensure_row (terminal);
-        VteCell *cell_start, *cell_end, *cell_col;
+        const VteCell *cell_start;
+        VteCell *cell_end, *cell_col;
+        gboolean cell_start_is_fragment;
         long col;
 
         g_assert(end >= start);
 
+        /* Remember whether the cell at start is a fragment.  We'll need to know it when
+         * handling the left hand side, but handling the right hand side first might
+         * overwrite it if start == end (inserting to the middle of a character). */
+        cell_start = _vte_row_data_get (row, start);
+        cell_start_is_fragment = cell_start != NULL && cell_start->attr.fragment;
+
         /* On the right hand side, try to replace a TAB by a shorter TAB if we can.
          * This requires that the TAB on the left (which might be the same TAB) is
          * not yet converted to spaces, so start on the right hand side. */
@@ -2967,8 +2975,7 @@ _vte_terminal_cleanup_fragments(VteTerminal *terminal,
 
         /* Handle the left hand side.  Converting longer TABs to shorter ones probably
          * wouldn't make that much sense here, so instead convert to spaces. */
-        cell_start = _vte_row_data_get_writable (row, start);
-        if (G_UNLIKELY (cell_start != NULL && cell_start->attr.fragment)) {
+        if (G_UNLIKELY (cell_start_is_fragment)) {
                 gboolean keep_going = TRUE;
                 col = start;
                 do {
