kovidgoyal/kitty · error

terminal sent a duplicate drag data request

Error message

terminal sent a duplicate drag data request

What it means

The terminal requested drag data for a MIME index it already requested earlier in the same drag. The kitten treats a repeated request as a protocol violation, finishes the drag with EINVAL, and errors out.

Source

Thrown at kittens/dnd/drag.go:281

	if errname == "" { // cancel drag
		dnd.lp.QueueDnDData(DC{Type: 'E', Y: -1})
	} else {
		dnd.lp.QueueDnDData(DC{Type: 'E', Payload: []byte(errname)})
	}
	dnd.reset_drag()
}

func (dnd *dnd) handle_data_request(idx int) (err error) {
	if idx < 0 || idx >= len(dnd.drag_status.offered_mimes) {
		dnd.finish_drag("EINVAL")
		return fmt.Errorf("terminal asked for drag data from MIME list with out of bounds index: %d", idx)
	}
	mime := dnd.drag_status.offered_mimes[idx]
	ds := dnd.drag_sources[mime]
	for _, dr := range dnd.drag_status.data_requests {
		if dr.index == idx {
			dnd.finish_drag("EINVAL")
			return fmt.Errorf("terminal sent a duplicate drag data request")
		}
	}
	dr := &data_request{drag_source: ds, index: idx}
	if ds.path == "" {
		dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx, Payload: utils.UnsafeStringToBytes(base64.RawStdEncoding.EncodeToString(ds.data))})
		dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx}) // EOF
		return
	} else {
		if ds.file != nil {
			ds.file.Close()
		}
		if ds.file, err = os.Open(ds.path); err != nil {
			dnd.finish_drag("EIO")
			return err
		}
	}
	dnd.drag_status.data_requests = append(dnd.drag_status.data_requests, dr)
	return dnd.send_data_for_data_request(len(dnd.drag_status.data_requests) - 1)

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Update kitty so kitten and terminal run matching protocol code
  2. Retry the drag operation — transient duplicates can occur if output was truncated
  3. Report upstream with a debug log of the escape sequences if reproducible
Defensive patterns

Strategy: try-catch

Try / catch

Treat as transient: catch the error, tear down drag state via reset_drag(), and let the user retry the drag.

Prevention

When it happens

Trigger: handle_data_request receives an idx already present in drag_status.data_requests — e.g. the terminal re-sent the request because the first response was lost or it mishandles the queue.

Common situations: Protocol version skew between kitten and terminal, terminal retrying after a dropped response, or a bug in request bookkeeping during rapid drag interactions.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/480bbbe6a2f7d9ec. Report an issue: GitHub.