Setting gutter markers on specific lines (by line number)

Based on the gutter example I have been trying to setting a gutter marker to set a gutter marker at invalid lines. When document changed a debounced handler is run (eventually the current document should be posted to the backend, returning list of lines where markers should be set, but for testing I just set a marker on every third line).

Obviously I have not figured out how achieve and the current code probably reflects my poor understanding of how to work with the current API.

    const invalidDirectiveMarker = new class extends GutterMarker {
      toDOM() { return document.createTextNode("ø") }

    const invalidDirectiveEffect = StateEffect.define({
      map: (val, mapping) => ({pos: mapping.mapPos(val.pos), on: val.on})

    const invalidDirectiveState = StateField.define({
      create() { return RangeSet.empty },
      update(set, transaction) {
        set =
        for (let e of transaction.effects) {
          if ( {
            if (e.value.on) {
              set = set.update({add: [invalidDirectiveMarker.range(e.value.pos)]})
            else {
              set = set.update({filter: (from) => from != e.value.pos })
        return set

   const debouncedChange = (function() {
      let timeout = null
      return function (doc, viewUpdate) {
        if (viewUpdate.docChanged) {
          timeout = setTimeout(() => {
            const {from: fromPos, to: toPos} = viewUpdate.view.viewport
            let stateEffects = []
            for (let pos = fromPos; pos <= toPos; pos++) {
              stateEffects.push(invalidDirectiveEffect.of({pos, on: !Boolean(pos % 3)}))
              effects: stateEffects
          }, 500)

    const invalidLineGutter = [
        markers: v => v.state.field(invalidDirectiveState),
        initialSpacer: () => invalidDirectiveMarker

    let state = createState({
      options: {
        extensions: [..., invalidLineGutter],
      onChange: debouncedChange,

This code results on a marker being set on every third line every time the document changes and the debounced handler is run, but none is cleared so markers are appended on said lines. I have been trying to figure out how to do this for the the best part of the last few days and am currently totally out of ideas. Would greatly appreciate if someone could point me in the right direction in how to achieve this.

If your effect occurs when the set of markers is recomputed, it seems like you’d want to replace the set of markers, rather than add to it, when it occurs.