<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot]]></title><description><![CDATA[<h1>Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot</h1>
<p dir="auto">(<code>Cannot read properties of null (reading 'sort')</code>)</p>
<h2>Summary</h2>
<p dir="auto">A full backup task aborts entirely when it reaches a ClickHouse-backed app (in my case Langfuse). The rsync syncer walks the app's data tree, but ClickHouse deletes a background-merge temp directory (<code>data/clickhouse/store/*/tmp_merge_*</code>) between enumeration and read. <code>readTree</code> gets <code>null</code> for that directory's contents and throws on <code>.sort()</code>, which propagates up and kills the whole task — not just the one app.</p>
<h2>Impact</h2>
<p dir="auto">This is the important part: <strong>one racy app aborts the entire backup run.</strong> In the run below the task died at app <strong>31 of 72</strong>, so all 41 remaining apps were silently left on the previous night's snapshot. The failure is timing-dependent (it only triggers if ClickHouse happens to be merging during the snapshot window), so backups appear intermittently broken with no config change on the user's side.</p>
<h2>Environment</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Cloudron version</td>
<td>9.2.0</td>
</tr>
<tr>
<td>OS</td>
<td>Ubuntu 24.04.2 LTS</td>
</tr>
<tr>
<td>Kernel</td>
<td>6.8.0-124-generic</td>
</tr>
<tr>
<td>Backup format</td>
<td>rsync, encrypted</td>
</tr>
<tr>
<td>Backup storage</td>
<td>Hetzner Storage Box over SSH (port 23)</td>
</tr>
<tr>
<td>Affected app</td>
<td>Langfuse (ClickHouse)</td>
</tr>
</tbody>
</table>
<h2>What happens</h2>
<p dir="auto">The same vanishing-temp-dir condition shows up twice in one snapshot. First it's caught harmlessly by the precondition <code>du</code>, which just warns and continues:</p>
<pre><code>du: cannot access '/home/yellowtent/appsdata/5edfb175-…/data/clickhouse/store/f0a/f0a84db1-…/tmp_merge_202606_23202_23297_19': No such file or directory
</code></pre>
<p dir="auto">Then it hits the rsync syncer, which does <strong>not</strong> tolerate it and crashes the task:</p>
<pre><code>backupupload: upload completed. error: TypeError: Cannot read properties of null (reading 'sort')
    at readTree (file:///home/yellowtent/box/src/syncer.js:31:47)
    at traverse (file:///home/yellowtent/box/src/syncer.js:130:30)
    at traverse (file:///home/yellowtent/box/src/syncer.js:136:17)
    … (recursion)
    at Object.sync (file:///home/yellowtent/box/src/syncer.js:159:5)
    at sync (file:///home/yellowtent/box/src/backupformat/rsync.js:166:63)
    at Object.upload (file:///home/yellowtent/box/src/backupformat/rsync.js:336:18)
    at async Object.upload (file:///home/yellowtent/box/src/backuptask.js:101:37)

tasks: setCompleted - 4798: {"result":null,"error":{"message":"Cannot read properties of null (reading 'sort')","reason":"External Error"},"percent":100}
</code></pre>
<h2>Root cause</h2>
<p dir="auto"><code>readTree</code> (<code>box/src/syncer.js:31</code>) reads a directory's entries and sorts them. When a subdirectory is removed between the initial <code>find</code>/enumeration and the per-directory read, the read returns <code>null</code> and <code>null.sort()</code> throws. The exception unwinds through <code>traverse</code> → <code>sync</code> → <code>rsync.js</code> → <code>backuptask.js</code>, so the whole task is marked failed rather than the single directory being skipped.</p>
<p dir="auto">This is <strong>expected, normal ClickHouse behaviour</strong>, not app misbehaviour: ClickHouse continuously creates and renames/deletes <code>tmp_merge_*</code> (and <code>tmp_insert_*</code>, <code>tmp_fetch_*</code>) directories under <code>store/&lt;uuid&gt;/</code> as background merges complete. Any tool that enumerates the store and then reads it will occasionally find a directory gone. ClickHouse upstream has hit and patched the equivalent race in their own tooling, e.g. <a href="https://github.com/ClickHouse/ClickHouse/pull/44874" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/ClickHouse/ClickHouse/pull/44874</a> — so accommodating it on the reader side is the standard approach.</p>
<h2>Suggested fix</h2>
<p dir="auto">Make <code>readTree</code> resilient to a directory disappearing mid-traversal instead of propagating <code>null</code>:</p>
<ul>
<li>Guard against a <code>null</code>/<code>undefined</code> entry list before <code>.sort()</code>.</li>
<li>On <code>ENOENT</code> (or a null read) for a directory that vanished after enumeration, treat it as empty / skip it and continue the walk, rather than aborting.</li>
</ul>
<p dir="auto">This matches how <code>du</code> already behaves in the same task (warn and continue) and would make every ClickHouse-based package back up reliably.</p>
<h2>Why this matters beyond Langfuse</h2>
<p dir="auto">Any package built on ClickHouse is affected the same way — Plausible, PostHog, SigNoz, Langfuse, etc. As more analytics apps adopt ClickHouse, more users will see intermittent, hard-to-diagnose full-backup aborts where the visible symptom (a stale backup on an unrelated app) is far from the actual cause.</p>
<h2>EDIT:</h2>
<h2>Workarounds in the meantime</h2>
<ul>
<li>Exclude the ClickHouse app from automatic backups so it can't abort the whole run, and back it up separately.</li>
<li>Note: stopping the app and then running <code>cloudron backup create --app &lt;fqdn&gt;</code> does <strong>not</strong> work, because Cloudron does not back up a stopped app. A quiesced backup therefore has to be a filesystem-level snapshot taken outside the platform. Otherwise, because the failure is a timing collision, simply re-running the scheduled backup usually clears it.</li>
</ul>
]]></description><link>https://forum.cloudron.io/topic/15663/backup-task-crashes-when-a-clickhouse-app-deletes-a-temp-merge-dir-mid-snapshot</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Jul 2026 16:31:30 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/15663.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 30 Jun 2026 06:47:06 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot on Mon, 06 Jul 2026 09:58:39 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/girish" aria-label="Profile: girish">@<bdi>girish</bdi></a> thank you, and thanks for confirming the fix ships in Cloudron 10.</p>
<p dir="auto">Adding one data point for anyone who finds this while still on 9.x: we hit the same crash again on 2026-07-06, on 9.2.0 (a build from before commit <code>33f3ca3</code>), so it recurs exactly as expected until the v10 upgrade:</p>
<pre><code>tasks: setCompleted - 4900: {"result":null,"error":{"message":"Cannot read properties of null (reading 'sort')","reason":"External Error"},"percent":100}
</code></pre>
<p dir="auto">Same app (Langfuse), same place: the task died at app 31 of 73, so the roughly 40 apps after it were left on the previous snapshot again. The <code>du</code> precondition logged the vanished directories first, this time a <code>delete_tmp_tmp_merge_*</code> variant alongside the usual <code>tmp_merge_*</code> ones, and then <code>readTree</code> threw during the upload.</p>
<p dir="auto">Until we are on 10 we have excluded the ClickHouse apps from the automatic schedule so a single mid-merge app cannot abort the whole run, and we re-run on the rare miss, which clears it. Glad to confirm the fix here once we upgrade, we have a reliable reproducer under merge load.</p>
]]></description><link>https://forum.cloudron.io/post/126455</link><guid isPermaLink="true">https://forum.cloudron.io/post/126455</guid><dc:creator><![CDATA[LoudLemur]]></dc:creator><pubDate>Mon, 06 Jul 2026 09:58:39 GMT</pubDate></item><item><title><![CDATA[Reply to Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot on Mon, 06 Jul 2026 09:49:26 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/loudlemur" aria-label="Profile: LoudLemur">@<bdi>LoudLemur</bdi></a> will be part of Cloudron 10 .</p>
]]></description><link>https://forum.cloudron.io/post/126453</link><guid isPermaLink="true">https://forum.cloudron.io/post/126453</guid><dc:creator><![CDATA[girish]]></dc:creator><pubDate>Mon, 06 Jul 2026 09:49:26 GMT</pubDate></item><item><title><![CDATA[Reply to Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot on Mon, 06 Jul 2026 09:42:50 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/girish" aria-label="Profile: girish">@<bdi>girish</bdi></a> thank you, that was a quick turnaround and much appreciated.</p>
<p dir="auto">Adding one more data point for anyone who finds this before the fix reaches a release. We hit the same crash again on 2026-07-06, still on 9.2.0 (a build from before commit <code>33f3ca3</code>), so it behaves exactly as expected until the patch ships:</p>
<pre><code>tasks: setCompleted - 4900: {"result":null,"error":{"message":"Cannot read properties of null (reading 'sort')","reason":"External Error"},"percent":100}
</code></pre>
<p dir="auto">Same app (Langfuse), same place: the task died at app 31 of 73, so the roughly 40 apps after it were left on the previous snapshot again. The <code>du</code> precondition logged the vanished directories first, this time a <code>delete_tmp_tmp_merge_*</code> variant alongside the usual <code>tmp_merge_*</code> ones, and then <code>readTree</code> threw during the upload.</p>
<p dir="auto">One question: which release will carry commit <code>33f3ca3</code>, so we know when to expect it? We have a reliable reproducer here under merge load and are glad to confirm the fix once it lands.</p>
<p dir="auto">In the meantime we have excluded the ClickHouse apps from the automatic schedule so a single mid-merge app cannot abort the whole run, and we re-run on the rare miss, which clears it as noted above.</p>
]]></description><link>https://forum.cloudron.io/post/126452</link><guid isPermaLink="true">https://forum.cloudron.io/post/126452</guid><dc:creator><![CDATA[LoudLemur]]></dc:creator><pubDate>Mon, 06 Jul 2026 09:42:50 GMT</pubDate></item><item><title><![CDATA[Reply to Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot on Tue, 30 Jun 2026 15:45:22 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/loudlemur" aria-label="Profile: loudlemur">@<bdi>loudlemur</bdi></a> thanks for the report. Fixed in <a href="https://git.cloudron.io/platform/box/-/commit/33f3ca39996ad5b3af2b5dd2320d1552dd8952c0" target="_blank" rel="noopener noreferrer nofollow ugc">https://git.cloudron.io/platform/box/-/commit/33f3ca39996ad5b3af2b5dd2320d1552dd8952c0</a></p>
]]></description><link>https://forum.cloudron.io/post/126277</link><guid isPermaLink="true">https://forum.cloudron.io/post/126277</guid><dc:creator><![CDATA[girish]]></dc:creator><pubDate>Tue, 30 Jun 2026 15:45:22 GMT</pubDate></item><item><title><![CDATA[Reply to Backup task crashes when a ClickHouse app deletes a temp merge dir mid-snapshot on Tue, 30 Jun 2026 13:21:31 GMT]]></title><description><![CDATA[<p dir="auto">Following up on our above report,  confirming this <strong>still reproduces on Cloudron 9.2.0</strong>, with the exact spot in the source in case it helps.</p>
<p dir="auto">We hit it on a real app backup just now:</p>
<pre><code>App backup error: Backup failed: Cannot read properties of null (reading 'sort')
</code></pre>
<p dir="auto">It reproduced on the <strong>second</strong> backup attempt under active ClickHouse merge load, so the race window isn't narrow.</p>
<p dir="auto">9.2.0 does add a guard, but it sits <strong>after</strong> the <code>.sort()</code>. In <code>box/src/syncer.js</code>, <code>readTree</code> is:</p>
<pre><code class="language-js">const names = safe.fs.readdirSync(dirPath).sort();   // line 31
if (!names) return [];                                // line 32
</code></pre>
<p dir="auto"><code>@cloudron/safetydance</code>'s <code>readdirSync</code> returns <code>null</code> on a vanished directory (the <code>ENOENT</code> when a ClickHouse <code>tmp_merge_*</code> part is renamed/removed mid-snapshot). So line 31 evaluates <code>null.sort()</code> and throws <strong>before</strong> the line-32 <code>if (!names)</code> guard can run — the guard is dead code for this crash, and the whole-server backup run still aborts.</p>
<p dir="auto">The fix is to null-check <strong>before</strong> <code>.sort()</code>:</p>
<pre><code class="language-js">const names = safe.fs.readdirSync(dirPath);
if (!names) return [];
names.sort();
</code></pre>
<p dir="auto">(or <code>(safe.fs.readdirSync(dirPath) || []).sort()</code>). The same file's <code>readCache</code> (around lines 22–23) already does it in this order — assign, null-check, then use — so this just makes <code>readTree</code> consistent with the existing pattern in the file.</p>
<p dir="auto">Happy to test a patch against a live ClickHouse-bundling app under merge load.</p>
]]></description><link>https://forum.cloudron.io/post/126275</link><guid isPermaLink="true">https://forum.cloudron.io/post/126275</guid><dc:creator><![CDATA[LoudLemur]]></dc:creator><pubDate>Tue, 30 Jun 2026 13:21:31 GMT</pubDate></item></channel></rss>