When two of my automations fought each other
I run a lot of scheduled jobs. Content pipelines, render queues, backup scripts, health checks, cleanup crons. Most of the time they don't know about each other and they don't need to. Each one has a job, it does that job, it exits. That's the whole appeal of automation: you write the thing once, it runs on a schedule, and you stop thinking about it.
The problem shows up when two of those jobs quietly touch the same resource without either one knowing the other exists. That's what happened to me. Two automations that had run fine independently for months started fighting over the same folder, and the result wasn't a crash. It was worse than a crash, because nothing failed loudly. Work just kept disappearing.
The setup
One automation was a content refill job. It scanned a folder for finished scripts, picked up any that didn't have an audio file yet, generated the audio, and tagged the row as done. It ran every few minutes on a schedule, because the alternative (running it once and leaving it) meant new scripts sat untouched for hours.
The second automation was a cleanup job. Its purpose was mundane: delete stale temp files older than a certain age so a fast-filling drive didn't fill up. It also ran on a schedule, independent of the first job, because disk space problems don't care what else is happening.
Neither job was new. Neither job was complicated. I'd run each one in isolation and watched it behave exactly as expected. The trouble only appeared once both were live on the same machine, touching folders that happened to overlap.
What actually went wrong
The refill job wrote its audio output to a temp location first, then moved the finished file into place once generation completed. That's a normal pattern, it avoids other processes picking up a half-written file. The cleanup job, meanwhile, was set to remove anything in temp folders past a certain age, on the assumption that anything sitting there that long was abandoned.
The two assumptions didn't line up. On a normal run, the refill job's temp file lived for seconds, well under the cleanup threshold. But when generation took longer than usual, or when a batch had a lot of items queued and processing stacked up, a temp file could sit there past the age cutoff. The cleanup job had no way to know that file was mid-flight rather than abandoned. It deleted what looked like garbage. The refill job then reached the move step, found nothing to move, and either errored quietly or, worse, marked the row as done anyway because the "did the file get created" check wasn't strict enough.
The output was a row in my tracking sheet marked complete with no audio file behind it. Not a pipeline crash. Not an error in any log I was checking. Just a gap that only showed up later, when something downstream expected a file that wasn't there.
Why it took a while to notice
This is the part that actually matters, more than the bug itself. Each automation had logging. Each one, read on its own, told a coherent story: the refill job said "processed and moved," the cleanup job said "removed stale temp files." Both statements were true from that job's point of view. Neither log said anything wrong.
The failure only existed in the gap between two logs that never referenced each other. I had to pull the timestamps from both jobs side by side to see that a cleanup run had touched a file seconds before the refill job expected to move it. That's the shape most automation conflicts take. Each system reports success because each system did exactly what it was told, on its own terms. The conflict lives in the timing, not in either script's logic.
I only found it because I went looking for a specific missing file and worked backward through timestamps. If I hadn't had reason to check that one file, this could have kept happening indefinitely, quietly eating a percentage of every batch and getting written off as "some percentage always fails, that's normal."
The actual fix
The fix wasn't clever. It was boring, which is usually a sign it's the right fix.
First, the cleanup job's age threshold got raised well past the realistic worst case for how long a temp file should legitimately exist, and it got scoped to a narrower set of folders instead of a broad temp directory that other jobs also used. Second, and more importantly, the refill job's "mark as done" step got a hard check: don't mark anything complete unless the final file actually exists on disk at that exact moment, not just "the generation step returned without an error." That second change was the one that mattered most, because it meant that even if something else touched the file, the pipeline would report a real failure instead of a false success.
Neither job needed to know about the other. They didn't need shared locks or a coordination layer between them. They just needed to stop making assumptions about a folder they didn't fully own, and to verify their own output instead of trusting their own success signal.
What I actually learned from this
The instinct after something like this is to reach for more infrastructure: file locks, a message queue, a coordination service that mediates every write. For two scripts touching one shared folder, that's overkill and it adds a new thing to maintain and debug later. The real fix was smaller: don't share a folder across automations unless you've thought through what happens when both are running at once, and never let a job report success based on "no error was thrown" when you can instead check "the thing I was supposed to produce is actually there."
The broader lesson is about how automations fail when you stack enough of them on one machine. Individually tested, individually logged, individually correct automations can still produce wrong outcomes once their side effects overlap in time. That's not a reason to avoid automating. It's a reason to be deliberate about what each job touches, and to make each job verify its own output rather than trust its own internal logic. A script that checks its work after the fact catches this kind of failure immediately. A script that only checks whether its own steps ran without throwing an exception will happily report success while the actual output is missing.
I don't think this is unique to my setup. Anyone running more than a couple of scheduled jobs on the same machine, touching adjacent folders, is one timing coincidence away from the same thing. It's worth an afternoon to go through your own automations and ask, honestly, which ones share a resource, and whether either one would notice if the other quietly deleted or altered something mid-run.
If you're building out your own stack of scheduled jobs and agents, this is the kind of failure mode worth designing against early, before you have a dozen scripts all assuming they're the only thing touching a given folder.
More on how I actually run automation and AI tooling day to day is on the [home page](/).
Get new guides and videos first — join the Telegram channel.