Skip to content

[Bug] Single-device infinite editor-bound sync loop in daily note (57-char Frankenstein chunk re-appended every ~4s) #25

@p3kj

Description

@p3kj

YAOS plugin version

1.6.1

Server deployment commit SHA

0c22149

Relevant logs or error text

Relevant logs or error text

Full redacted diagnostics attached: sync-diagnostics-2026-04-20T17-54-07-037Z-t14.redacted.json. Host / vaultId / token prefix scrubbed; everything else intact.

Condensed excerpt - recentEvents.plugin. Same log line every ~4 seconds, 233 consecutive iterations, delta strictly +57 chars each tick:

2026-04-20T14:27:04.634Z  syncFileFromDisk: recovering "50_Journal/2026-04-20.md" (editor-bound local-only divergence: 28217 -> 28274 chars)
2026-04-20T14:27:08.634Z  syncFileFromDisk: recovering "50_Journal/2026-04-20.md" (editor-bound local-only divergence: 28274 -> 28331 chars)
2026-04-20T14:27:12.635Z  syncFileFromDisk: recovering "50_Journal/2026-04-20.md" (editor-bound local-only divergence: 28331 -> 28388 chars)
...
editor-bound local-only divergence: 41441 -> 41498 chars

The file grew from 28,217 -> 41,498 chars over ~6 minutes. The loop only stopped when the websocket provider disconnected (14:42:22Z). It did not self-heal.

Single device during the loop

During the 14:27 -> 14:42 window, only client t14 (Linux desktop) was active. Mobile was not open (Obsidian may have been in the background on the phone, but not in use, not focused, no activity originating from it in the log). No other writer / device / generation bump appears in the diagnostics during the loop.

What the 57-char chunk actually is

The affected file is a Templater-generated daily note with two ```tasks code blocks that share structure (see template below). The 57-char chunk being appended on every tick is not a slice of either block - it is a Frankenstein mix of pieces from both of them:

\n## Overdue            <- from Overdue section header
\n```tasks              <- ``` opener (same in both blocks)
\nnot                   <- truncated from "not done" (Overdue)
\nsort by priority      <- from Today's Focus (Overdue has "sort by due")
\nshort mode            <- present in both
\n```                   <- ``` closer

Original template content of the two blocks:

## Today's Focus
```tasks
(scheduled on {{query.file.filenameWithoutExtension}}) OR (due on {{query.file.filenameWithoutExtension}})
sort by priority
short mode
```

## Overdue
```tasks
not done
(due before {{query.file.filenameWithoutExtension}}) OR (scheduled before {{query.file.filenameWithoutExtension}})
sort by due
short mode
```

The two blocks share the ```tasks opener and the short mode / ``` closer. The stable 57-char delta looks like the divergence-recovery diff mis-aligning across those repeated anchors and settling into a byte-stable wrong merge that it keeps re-applying.

Final state in diagnostics

At the moment of capture the system is green:

  • hashDiff.matchingCount = 501, no missing / no mismatches.
  • Editor / disk / CRDT hashes identical for both open files.
  • undoManagerMatchesFacet: false for both open files (not sure if relevant).

What you did

What I did (reproduction, best recollection)

  1. Opened today's daily note 50_Journal/2026-04-20.md on t14. The note was freshly generated from the Templater daily template above (two ```tasks queries + one ```base block).
  2. Started editing the Work checkbox list (adding - [ ] <text> lines, then an empty - [ ], then more text). Czech text in short bursts, going back to correct.
  3. Shortly after, an empty checkbox started being repeated by sync - local input fought incoming changes, same line re-appeared.
  4. I tried to select-and-delete the affected region to stop it. The selection very likely extended downward into the ```tasks block area below the checkbox list.
  5. Stepped away from the machine. By the time diagnostics logging captures the file it is already at 28,217 chars and the oscillating 57-char diff has aligned on the Frankenstein chunk described above. Loop continues uninterrupted for ~6 minutes.
  6. Loop stops only because t14 loses the websocket connection at 14:42:22Z.
  7. Hours later I opened Obsidian on mobile (same YAOS room), while t14 was still offline, and manually stripped the duplicated content from the note.
  8. When t14 came back online (17:51:03Z, gen 13, authoritative reconcile), it correctly pulled the manually-cleaned state from the server (470 chars), fired one more 470 -> 527 divergence, then skipping ... (editor-bound, recovery lock), and settled. The "recovery" tail in the log is a side-effect of my manual mobile cleanup, not YAOS recovering on its own.

Environment

  • Affected client during loop: Linux (Arch, kernel 6.19), Obsidian desktop, device t14
  • Second client used for manual recovery (later, t14 offline): Obsidian mobile, same YAOS room
  • Only one client active at any given time: t14 during the loop, mobile during the cleanup
  • YAOS: 1.6.1 (both clients)
  • Tasks plugin: installed and active; affected file contains two ```tasks queries
  • Templater: installed (daily note is Templater-generated)

Notes / hypotheses for debugging

  • Trigger: editing a checkbox / bullet list that sits above two structurally similar ```tasks code fences.
  • The divergence-recovery path (syncFileFromDisk ... editor-bound local-only divergence) entered a loop where a byte-stable 57-char diff was re-applied every ~4 s for ~6 minutes.
  • The diff is a hybrid across two ```tasks blocks that share anchors (```tasks, short mode, ```). Plausible mechanism: a line-based diff / recovery step mis-aligning on the repeated anchors and producing a minimal edit that is both "applied" to the editor and "not yet merged" according to CRDT state, so the next tick re-applies it.
  • Critically: only one client was active during the loop. This appears to rule out the "two cursors close together on the same file" hypothesis discussed in Sync loop glitching making edits impossible #22 as a necessary condition for this symptom.
  • The loop did not self-heal; only disconnection + external manual cleanup stopped it.
  • Minor: undoManagerMatchesFacet: false in the final snapshot for both open files.

Attachment

sync-diagnostics-2026-04-20T17-54-07-037Z-t14.redacted.json - host / vaultId / token prefix redacted, rest of the snapshot (events, state, hashDiff, openFiles, blobSync) intact.

Related

Same YAOS version and similar surface symptom as open issue #22 ("Sync loop glitching making edits impossible"). This report is scoped narrower: single active client, Linux desktop, captured diagnostics, concrete content trigger (checkbox edit adjacent to two similar ```tasks fences), and evidence that the loop does not self-heal.


  • I used Claude Code to help analyze the diagnostics file and structure this report to the best of my abilities. I hope it will be helpful.
  • I really like this plugin! Great work!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions