<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Race-Conditions on ErrorZap</title><link>https://errorzap.com/tags/race-conditions/</link><description>Recent content in Race-Conditions on ErrorZap</description><image><title>ErrorZap</title><url>https://errorzap.com/og.png</url><link>https://errorzap.com/og.png</link></image><generator>Hugo</generator><language>en-US</language><copyright>ErrorZap</copyright><lastBuildDate>Fri, 06 Nov 2026 09:00:00 -0700</lastBuildDate><atom:link href="https://errorzap.com/tags/race-conditions/index.xml" rel="self" type="application/rss+xml"/><item><title>Partial Files Are Not Finished Files</title><link>https://errorzap.com/posts/partial-files-are-not-finished-files/</link><pubDate>Fri, 06 Nov 2026 09:00:00 -0700</pubDate><guid>https://errorzap.com/posts/partial-files-are-not-finished-files/</guid><description>A scanner found an audio file while it was still being written and taught me that a filename is not a completion receipt.</description><content:encoded><![CDATA[<p>The file existed. That was the problem.</p>
<p>An audio pipeline was generating long tracks, copying them between stages, and feeding them into another scanner. The scanner watched a directory and did what scanners do: it saw a new filename and assumed there was a new file to process.</p>
<p>Except the producer was still writing it.</p>
<p>The scanner opened a half-finished track, read whatever bytes happened to exist at that moment, and produced a failure that looked like corrupted audio. The source was not corrupt. The source was unfinished.</p>
<h2 id="existence-is-a-weak-signal">Existence is a weak signal</h2>
<p>Filesystems make partial work visible unless we deliberately hide it.</p>
<p>A process can create a destination path, write for several minutes, flush buffers, update metadata, and close the handle. During most of that time, other programs can see the name. A naive watcher treats the first directory event as a completion event.</p>
<p>Those are not the same event.</p>
<p>The safe pattern is boring and effective:</p>
<ol>
<li>Write to a clearly temporary name such as <code>chapter-08.mp3.partial</code>.</li>
<li>Flush and close it.</li>
<li>Validate size, duration, checksum, or format.</li>
<li>Rename it to <code>chapter-08.mp3</code> on the same filesystem, where a rename is atomic.</li>
<li>Let downstream scanners ignore every <code>.partial</code> file.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>chapter-08.mp3.partial  -&gt; invisible to consumers
</span></span><span style="display:flex;"><span>          validate
</span></span><span style="display:flex;"><span>          rename
</span></span><span style="display:flex;"><span>chapter-08.mp3          -&gt; finished contract
</span></span></code></pre></div><p>The rename is the receipt.</p>
<h2 id="stable-size-is-helpful-not-sufficient">Stable size is helpful, not sufficient</h2>
<p>Another common fix is to wait until a file&rsquo;s size stops changing. That helps, but it is not proof.</p>
<p>A producer may pause while waiting on a network, encoder, or API. The file can remain the same size for thirty seconds and then continue. Conversely, buffered writes can make size updates arrive in bursts. &ldquo;Stable for a moment&rdquo; is a heuristic.</p>
<p>Stronger completion signals include:</p>
<ul>
<li>producer-controlled atomic rename (same volume, not a cross-disk copy);</li>
<li>a companion manifest written after validation;</li>
<li>expected byte length and checksum;</li>
<li>a media probe that decodes cleanly through the expected duration;</li>
<li>a database status transition committed after the file closes.</li>
</ul>
<p>The producer knows when it is done. Make it say so.</p>
<h2 id="consumers-should-still-be-suspicious">Consumers should still be suspicious</h2>
<p>Even a clean handoff can encounter interrupted copies, disk-full conditions, or older software that ignores the convention. Downstream jobs should reject obviously partial input and record why.</p>
<p>For audio, that may mean probing duration and codec before import. For archives, it means listing and testing entries. For downloads, it means checking expected length and hash. For documents, it may mean opening the container rather than trusting the extension.</p>
<p>The rule scales far beyond media. Database dumps, camera exports, backups, reports, and generated websites all suffer when a path is mistaken for a promise.</p>
<p>The fix is to define what &ldquo;finished&rdquo; means in a way another process can test.</p>
<p>A file with a final-looking name is evidence that someone started. A validated atomic handoff is evidence that they finished.</p>
]]></content:encoded></item></channel></rss>