Anatomy of a deceptive "works on my machine" bug

You're standing on the throttle, you're standing on the brakes
In the groove 'til you make a mistake
Sometimes you are the windshield
Sometimes you are the bug

"The bug", Dire Straits

Introduction

The phrase "works on my machine" is a classic in our field, often said with a mix of confidence and frustration. We've all been on one side of that conversation or the other. I recently found myself at the center of a particularly difficult case that wasn't just a simple environment issue, but a complex combination of technical quirks, communication gaps, and one very specific "ghost" on my local machine. Here's a breakdown of what happened.

The initial situation

It started with a colleague, let's call him colleague A, who created a pull request for a test technology migration. His PR used version x of a specific test framework, along with a custom extension for that framework that I had developed. The PR was solid and worked well.

After reviewing his work, I saw an opportunity for a different architectural approach. Before suggesting major changes, I wanted to confirm my idea was viable. So, I branched off his PR to build a quick proof-of-concept.

My approach and first signs of trouble

In my branch, I implemented my new architectural design. While I was at it, I also updated the test framework from version x to the newer version y and left the other dependencies as they were. After confirming everything worked on my end, I created my own PR and put it up for review.

Soon after, colleague A reported that he couldn't get my branch to work. He was getting a Maven dependency error.

My immediate reaction was one of confusion. I had just run it successfully. I replied, "No, it works fine." My confidence was boosted when another colleague, let's call him B, also reported that it worked for him. At this point, I was convinced the problem was isolated to colleague A's local setup. We spent a good amount of time trying to debug his environment, but with no success.

Investigation and realization

The situation didn't make sense. It worked for two of us but failed for one. When debugging hits a wall like this, it's usually because a core assumption is wrong. My assumption was that our build environments were identical.

Then it hit me. I had updated the framework to version y, which I knew had a breaking change. This change required our internal extension to be updated as well. The version of the extension in my pom.xml was still the old one; logically, it should have been incompatible and my build should have failed. So why did it work?

The answer was in how Maven resolves dependencies. It checks the local repository (~/.m2/repository) first. Months ago, I had done the work to make our extension compatible with framework version y. During that process, I must have installed a test build to my local repository with the old version number before officially releasing it under a new version.

My machine was using this locally-built, unreleased, and compatible artifact. Colleague A, on the other hand, was correctly pulling the old, official artifact from our remote storage, which was incompatible with framework version y.

To confirm this, I deleted the extension from my local Maven repository and reran the build, it pulled the officially published version of my extension.

It finally failed with the exact same error colleague A had been seeing!

Finding a common ground and final fix

With this new information, I first clarified with colleague B which PR he had tested. It turned out he had reviewed colleague A's original PR, not mine—a simple communication failure. Once he pulled my actual branch and ran it, he got the same dependency error. Finally, the behavior was consistent for all of us.

The next step was to update the pom.xml in my PR to use the correct, newest version of our extension. This solved the immediate incompatibility with framework version y.

However, this introduced one final, smaller issue. The newest extension version also had a breaking change of its own that required some adjustments in our test code. The "ghost" version on my machine had been an intermediate build that was compatible but didn't have these final API changes yet. So yet another layer of mystery we had to uncover...

After making those last code adjustments, I pushed the fix. My PR now worked for everyone.

A bit of reflection

Looking back, this incident was a perfect storm of small, unrelated issues. A technical detail in Maven's dependency resolution, a minor miscommunication about which PR was being reviewed, and a forgotten artifact on my local machine all combined to create a very confusing situation.

This experience reinforced a few key practices for me. First is the importance of a clean build environment, as our CI servers have, to ensure what I'm testing is what everyone else will get. Second is the value of isolating changes—bundling an architectural refactor with a dependency upgrade made this much harder to diagnose.

Ultimately, it was a valuable, if humbling, reminder of how complex our development environments are and how a little-known detail can lead to a major headache. I'm grateful we were able to untangle it, and it's a lesson I'll carry with me to the next "works on my machine" moment.