ssssssss-team/spider-flow · error · Error

Inserting collapsed marker partially overlapping an…

Error message

Inserting collapsed marker partially overlapping an existing one

What it means

markText()/setBookmark() with {collapsed: true} refuse to create a collapsed marker that partially overlaps another collapsed marker on the same line. Partial collapse overlap is unrepresentable in the rendering model, so CodeMirror throws.

Solutions

  1. Check for existing collapsed marks first (cm.findMarksAt / cm.getAllMarks with mark.collapsed) and skip or expand the new range to fully contain/avoid them
  2. Unfold (mark.clear()) the conflicting collapsed range before inserting the new one
  3. Use non-collapsed marks (className only) when overlapping highlighting is needed

Example fix

// before
cm.markText(from, to, {collapsed: true});
// after
var conflicting = cm.findMarksAt(from).concat(cm.findMarksAt(to))
  .some(function(m){ return m.collapsed; });
if (!conflicting) { cm.markText(from, to, {collapsed: true}); }
Defensive patterns

Strategy: validation

Validate before calling

function hasCollapsedConflict(cm, from, to) {
  var lines = [from.line];
  if (to.line !== from.line) lines.push(to.line);
  return lines.some(function(l) {
    return cm.findMarksAt({line: l, ch: 0}).some(function(m) { return m.collapsed; });
  });
}
if (hasCollapsedConflict(cm, from, to)) { /* clear or skip */ }

Try / catch

try {
  var mark = cm.markText(from, to, {collapsed: true});
} catch (e) {
  if (/partially overlapping/.test(e.message)) {
    var mark = cm.markText(from, to, {className: "my-highlight"}); // non-collapsed fallback
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling cm.markText(from, to, {collapsed: true}) where the range partially intersects an existing collapsed range (shared endpoint overlap covering only part of the existing range) on from.line or to.line.

Common situations: Code-folding plugins folding overlapping regions, users folding already-folded sub-regions, or programmatic annotations applying collapsed markers over widget bookmarks.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of ssssssss-team/spider-flow@c799cca99c (2026-09-08). Data as JSON: /api/errors/73c0afdeae4d5933. Report an issue: GitHub.

Appendix: source

Thrown at spider-flow-web/src/main/resources/static/js/codemirror/codemirror.js:5961

    // Ensure we are in an operation.
    if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }

    var marker = new TextMarker(doc, type), diff = cmp(from, to);
    if (options) { copyObj(options, marker, false); }
    // Don't connect empty markers unless clearWhenEmpty is false
    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
      { return marker }
    if (marker.replacedWith) {
      // Showing up as a widget implies collapsed (widget replaces text)
      marker.collapsed = true;
      marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
      if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
      if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
    }
    if (marker.collapsed) {
      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
        { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
      seeCollapsedSpans();
    }

    if (marker.addToHistory)
      { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }

    var curLine = from.line, cm = doc.cm, updateMaxLine;
    doc.iter(curLine, to.line + 1, function (line) {
      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
        { updateMaxLine = true; }
      if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
      addMarkedSpan(line, new MarkedSpan(marker,
                                         curLine == from.line ? from.ch : null,
                                         curLine == to.line ? to.ch : null));
      ++curLine;
    });
    // lineIsHidden depends on the presence of the spans, so needs a second pass
    if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {

View on GitHub (pinned to c799cca99c)