This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.
What Happened
AutoSubs is an open-source tool that generates AI-powered subtitles inside DaVinci Resolve. It worked fine - until Resolve was installed somewhere other than the default location.
When Resolve lives in a custom path (like D:\software\Davinci\), multiple versions of avutil*.dll end up sitting side by side - avutil-56.dll, avutil-58.dll, sometimes more. AutoSubs' Lua loader wasn't built for that. It would throw:
Couldn't find exact match for pattern "avutil*.dll."
And just like that, AutoSubs refused to load inside Resolve. No subtitles, no connection, nothing worked.
The Root Cause
The culprit was load_library() inside libavutil.lua. The original code hard-assumed exactly one matching DLL would ever exist:
assert(#files == 1 and files[1].IsDir == false, ...)
On a standard install, that's true. On a custom install with multiple avutil versions present, it's not - and the assert just blows up the entire load process.
My First Fix
The plan was simple:
- Accept one or more matches instead of exactly one
- Sort by filename and automatically pick the newest version
- Wrap the load in
pcallso a bad file doesn't crash everything
local files = bmd.readdir(...)
if #files >= 1 then
local best_file = nil
for _, file in ipairs(files) do
if not file.IsDir then
if best_file == nil or file.Name > best_file.Name then
best_file = file
end
end
end
if best_file ~= nil then
local ok, lib = pcall(ffi.load, files.Parent..best_file.Name)
if ok then return lib end
end
end
assert(false, ...)
I tested it on Windows 11 with both avutil-56.dll and avutil-58.dll present in a custom path. AutoSubs loaded, subtitles generated, connection was stable. I opened the PR feeling good about it.
The Twist I Didn't See Coming
A day later, an automated code review bot flagged something I'd completely missed: while rewriting the file, my fix had quietly deleted two functions - frame_from_timecode() and timecode_from_frame().
Turns out those weren't dead code - the rest of the app still called them. Removing them meant features like JumpToTime and render progress tracking would now crash with attempt to call method ... (a nil value), even though the DLL itself was loading perfectly fine.
That's the part that got me. My fix solved the exact bug I was staring at, and quietly introduced a new one I wasn't.
The maintainer confirmed it directly in review:
The underlying issue is valid, but this PR removes
frame_from_timecode()andtimecode_from_frame(), both of which are still used by AutoSubs. This would break Resolve timeline/timecode functionality. We should keep those functions and only updateload_library()to tolerate multiple matching libavutil binaries.
What I Learned
The root-cause fix - loosening an overly strict assert - was correct. But because I rewrote more of the file than the bug actually required, I broke functionality the original bug report never even mentioned.
Debugging isn't just "does my fix solve the bug I'm looking at." It's also "what else does this code touch that I didn't think to check?" A well-tested fix can still quietly delete something important - because you only test the scenarios you're thinking about, not the ones you accidentally removed.
Next time, I'm changing the smallest possible surface area to fix a bug, and grepping the whole codebase for every function I'm about to touch before I touch it.

Top comments (0)