This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.


"The best debugger is a well-rested mind armed with the right tools and a stubborn refusal to give up."


The Call to Adventure

It started like any other day. I was browsing GitHub, coffee in hand, when I stumbled across a repository that made me pause. The issue tracker was filled with bug reports that all had something in common. They were being ignored. Not because the maintainers did not care, but because these bugs were hard. They were the kind of bugs that hide in race conditions, platform edge cases, and security blind spots. The kind that make you stare at the screen for hours before the answer finally clicks.

I am Aniruddha Adak, an AI Agent Engineer and Full-Stack Developer who builds autonomous systems. You can find my work on GitHub, read my blog at aniruddha-adak.vercel.app, or follow me on X and DEV.

Over the past several months, I went on a bug-smashing spree that resulted in 373 merged pull requests across the open source ecosystem. This is the story of the most chaotic, educational, and rewarding debugging journeys from that adventure.


Story One: The Security Breach Nobody Saw Coming

The Project

cognee is an open source AI memory infrastructure project. Think of it as the long-term memory system for AI agents. It stores, retrieves, and connects knowledge across conversations. It is ambitious, complex, and used by developers who need their AI systems to remember things.

The Discovery

I was reviewing the API layer, tracing how settings were updated. The POST /api/v1/settings endpoint caught my attention. It accepted a JSON payload and updated global configuration directly. No privilege check. No role verification. Just raw, unauthenticated power handed to anyone with a login token.

My stomach dropped.

In a production deployment, this meant any user could change LLM API keys, modify database connections, alter authentication settings, or disable security features entirely. This was not a subtle bug. This was a full system takeover waiting to happen.

The Investigation

I opened the codebase in the Antigravity agentic IDE and asked the AI to trace the authorization flow. Within seconds, it mapped the middleware stack and identified the gap. The settings route was registered without the admin guard that protected other sensitive endpoints.

I checked the test suite. There were tests for settings updates, but none tested authorization failure. The bug had been sitting there, invisible to the test suite, invisible to code review, invisible to everyone.

The Fix

GitHub logo fix(security): restrict global settings and disable public registration #3115

Closes #3084

This PR addresses the security vulnerabilities reported in #3084:

  • Requires superuser privileges for POST /api/v1/settings to prevent global configuration takeover.
  • Fully masks LLM and VectorDB API keys in GET /api/v1/settings to prevent leaking key prefixes.
  • Adds a COGNEE_PUBLIC_REGISTRATION_ENABLED environment variable to allow administrators to disable public self-registration.

The fix was two lines of code. A decorator. require_superuser(). That was it. Two lines that closed a security hole you could drive a truck through.

I also masked LLM credentials in the response payload so that even authorized users would not see sensitive API keys in settings read responses.

The Lesson

The simplest fixes are often the most important. This two-line change had more security impact than any complex feature I could have built. Always audit your authorization matrix. Always test the negative cases. Always assume that if a permission check is missing, someone will find it.


Story Two: The Windows Path That Broke Everything

The Discovery

A user reported OS Error 3 on Windows when using local vector database storage. The error message was cryptic. The path looked fine. But LanceDB subprocesses were failing to open database files.

The Deep Dive

I fired up Antigravity and asked the AI to research Windows path handling. The answer came back immediately. Windows has a legacy maximum path length of 260 characters. When you exceed that, the API returns Error 3: The system cannot find the path specified. Even though the path exists.

The fix is to use the \\\\?\\ prefix, which enables extended-length paths up to 32,767 characters. But you cannot just slap that prefix on every path. It only works with absolute paths. It breaks relative paths. And it is Windows-only.

The Investigation

I traced the vector_db_url through the cognee codebase. The path was being constructed in Python, passed to LanceDB, which then spawned a subprocess. The subprocess was where the failure occurred. The prefix needed to be added at the exact point where the path crossed from Python into the native layer.

I spun up a Windows VM and reproduced the bug. The path was only 180 characters, well under 260. But LanceDB was adding its own internal directory structure, pushing the effective path past the limit. The error was happening in code the user never saw.

The Fix

I implemented runtime platform detection. On Windows, the code now normalizes the path to absolute form and adds the extended-length prefix before passing it to LanceDB. On Linux and macOS, the path is passed through unchanged.

The key insight was that the fix had to be transparent. Users should not need to know about Windows path limits. The software should just work.

The Lesson

Cross-platform bugs are the hardest to find and the easiest to ignore. Most developers work on Linux or macOS. Windows users suffer in silence. When someone reports a Windows bug, treat it as a gift. They are telling you about a whole category of problems your development environment will never reveal.


Story Three: The Ghost Lock That Haunted Production

The Project

The hold_lock context manager in cognee was supposed to provide safe, concurrent access to shared resources. It was simple. Acquire a lock. Do some work. Release the lock. What could go wrong?

The Discovery

Error reports were coming in about unhandled exceptions during cleanup. The stack traces pointed to the lock release statement. But the lock was being acquired successfully. How could releasing it fail?

The Investigation

I studied the code. The pattern was:

lock = acquire_lock()
try:
    yield lock
finally:
    lock.release()

Enter fullscreen mode Exit fullscreen mode

Looks fine, right? Wrong.

If acquire_lock() failed and raised an exception, the finally block would still execute. But lock would be undefined or in an invalid state. The release would fail with its own exception, masking the original acquisition failure.

In high-concurrency environments, lock acquisition fails more often than you think. Timeouts, deadlocks, resource exhaustion. When that happens, the cleanup code makes things worse by throwing a second exception.

The Fix

GitHub logo Safely release lock in hold_lock context manager #7

fixes #3294. This PR ensures that hold_lock only attempts to release the lock if it was successfully acquired. We now initialize the lock variable to None, attempt to acquire the lock inside the try block, and verify that the lock is not None in the finally block before calling release_lock.

I restructured the pattern:

lock = None
try:
    lock = acquire_lock()
    yield lock
finally:
    if lock is not None:
        lock.release()

Enter fullscreen mode Exit fullscreen mode

Now the release only happens if the lock was actually acquired. The original exception propagates cleanly. No ghost exceptions haunting the cleanup.

The Lesson

Cleanup code needs the same scrutiny as main logic. We tend to focus on the happy path. But software spends most of its life on unhappy paths. The finally block is where bugs go to breed. Never assume a resource was successfully acquired before trying to release it.


Story Four: The Tests That Lied About Windows

The Discovery

While contributing to openclaw, an agentic AI framework, I noticed something disturbing. The test suite had if (process.platform === 'win32') { return; } scattered throughout. Entire categories of tests were being skipped on Windows.

The Investigation

I asked a simple question. Why?

The comments said "Windows does not support symlinks." But that has not been true since Windows Vista. Windows has supported symlinks since 2007. It requires specific permissions, and directory junctions work even without admin rights. The tests were skipping Windows based on a decade-old assumption.

This meant bugs in symlink handling, path resolution, and file operations were going completely undetected on the most common desktop operating system in the world.

The Fix

GitHub logo test(browser): replace broad win32 skip with dynamic directory symlink check #90365

Related: #90275

What Problem This Solves

The output-directories.test.ts test had a broad, unconditional skip for win32 platforms, meaning symlink rejection wasn't fully tested on Windows machines that do support symlinks/junctions. Additionally, the initial symlink capability probe was leaving uncleaned directories and failing linters.

Why This Change Was Made

To ensure that tests adapt dynamically to the environment's capabilities rather than blindly skipping based on OS. This makes the test suite more robust and accurate. The probe was updated to properly clean up after itself using fsSync.rmSync in a finally block and correctly evaluate if directory symlinks can be created on the given system without polluting the temp directory.

User Impact

No direct end-user impact. Improves test reliability and Windows developer experience by correctly evaluating symlink capabilities and ensuring no temporary directory pollution during testing.

Evidence

Tests run and pass successfully. All linters (including oxlint) pass on the updated probe.

✓  extension-browser  ../../extensions/browser/src/browser/output-directories.test.ts (2 tests) 270ms

 Test Files  1 passed (1)
      Tests  2 passed (2)

GitHub logo test: make install-safe-path symlink tests compatible with Windows #90275

Summary

  • Run the existing install-path symlink boundary tests on Windows when directory junctions are supported.
  • Use Windows junctions for directory links while preserving dir symlinks elsewhere.
  • Keep production install-path behavior unchanged.
  • Treat temporary-directory or cleanup failures in the capability probe as unsupported test environments instead of failing module import.

Linked context

No linked issue. This is a test portability improvement for existing install-path boundary coverage.

Real behavior proof

  • Behavior addressed: Three install-safe-path symlink boundary tests were unconditionally skipped on Windows.
  • Real environment tested: Native Windows Azure VM (Standard_D4ads_v6) through Crabbox.
  • Exact steps or command run after this patch: node scripts/run-vitest.mjs src/infra/install-safe-path.test.ts
  • Evidence after fix: Native Windows console output from Crabbox lease cbx_be4230e2069c, run run_0fb83e164185:
RUN  v4.1.8 C:/repo/openclaw

✓ infra src/infra/install-safe-path.test.ts (24 tests) 525ms

Test Files  1 passed (1)
Tests       24 passed (24)
  • Observed result after fix: The directory-junction cases executed successfully on native Windows instead of being skipped by platform.
  • What was not tested: No end-user install flow was exercised because the patch changes tests only.
  • Proof limitations or environment constraints: The tests still skip when the host cannot create directory links.
  • Before evidence: Current main uses it.runIf(process.platform !== "win32") for all three cases.

Tests and validation

  • node scripts/run-vitest.mjs src/infra/install-safe-path.test.ts
  • node scripts/run-oxlint.mjs src/infra/install-safe-path.test.ts
  • Native Windows Crabbox: 24/24 tests passed
  • Blacksmith Testbox tbx_01kv72nvfyz4fgpny8cyn48xfr: pnpm check:changed
  • .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main

Risk checklist

  • Did user-visible behavior change? No
  • Did config, environment, or migration behavior change? No
  • Did security, auth, secrets, network, or tool execution behavior change? No
  • Highest-risk area: Windows directory-link capability detection in the test harness.
  • Mitigation: Capability-gated execution plus direct native-Windows proof.

Current review state

  • Next action: Refresh CI on the rebased head and merge when required checks pass.
  • Addressed review comments: Temporary directory creation and cleanup are contained by the probe; module-level probing remains intentional because Vitest evaluates skipIf during test declaration.

GitHub logo test: make qqbot symlinked media helper test robust on Windows #90223

Replaces the hardcoded Windows skip in the QQ Bot file-utils test with a dynamic file-symlink capability check. If file symlinks are supported by the environment, the test executes. Otherwise, it skips gracefully while keeping coverage active on capable hosts.

What Problem This Solves

The symlinked local-media helper test should reject symlinked media paths when the runtime can create file symlinks, but it should not fail the suite on Windows or restricted environments where file symlink creation is unavailable. Gating the test on actual capability avoids false negatives while preserving the security regression coverage where the behavior can be exercised.

Evidence

  • Windows Vitest proof from the contributor: extensions/qqbot/src/engine/utils/file-utils.test.ts completed with 1 passed test file, 4 passed tests, and 1 skipped symlink test when file symlink creation was unavailable.
  • The follow-up repair commit cb7d5a162e24f7ec5be6985e97b2b74ae45b20f9 changes the probe to async fs.promises APIs and skips solely on !canCreateFileSymlinks, which addresses the stale Copilot comments about non-Windows restricted environments and synchronous import-time filesystem work.
  • Current PR CI is otherwise green; the remaining failed check was the external-PR body proof gate requiring these authored sections.

Instead of skipping based on platform, I implemented dynamic capability checks. The tests now ask the operating system: "Can you create symlinks?" If yes, the test runs. If no, it skips with a clear explanation.

For directory operations, I used Windows junctions instead of symlinks. Junctions have been supported since Windows 2000 and do not require special privileges. For file symlinks, I check capability at runtime.

The Lesson

Assumptions are the root of all evil in software. Platform checks, version checks, feature detection. They all age poorly. Capability detection is the only approach that stays correct over time. Write code that asks what the system can do, not what you think it is.


Story Five: The AI That Could Not Tell Healthy from Sick

The Project

opensre is a site reliability engineering platform that uses LLMs to classify alerts and identify root causes. The promise is powerful. Feed it your monitoring data, and it tells you what is wrong.

The Discovery

The synthetic QA tests were failing. The LLM was classifying healthy alerts as noise. Specifically, scheduled maintenance checks and healthy status pings with severity information and normal state were being marked is_noise=True.

This was catastrophic. If the system filters out healthy signals as noise, it cannot establish a baseline. Without a baseline, every alert looks like an emergency. Engineers burn out. Pager fatigue sets in. Trust in the platform evaporates.

The Investigation

Using Antigravity with Google AI, I traced the classification pipeline. The problem was in the LLM extraction step. The prompt was not giving the model enough context to distinguish between "this alert is unimportant" and "this alert indicates a healthy state."

I needed to expand the training data. Specifically, the _build_database_directive() function needed to learn about:

  • Compositional faults where multiple issues mask each other
  • Red herrings in alert patterns
  • Dual fault symptoms versus single root causes
  • Missing storage metrics and how to infer them
  • RDS-specific scenarios like connection exhaustion

The Fix

GitHub logo fix(synthetic-qa): Identify healthy alerts correctly (#596) #618

This PR fixes the 000-healthy synthetic-qa failure (Fixes: #596).

Cause:

  1. The LLM extraction step was classifying 'healthy' and scheduled checks (which have severity 'info' and state 'normal') as is_noise=True.
  2. Even if it bypassed noise extraction, the LLM was assuming it didn't need to gather investigation metrics because the alert explicitly said the database was normal, leading to an empty sequence of actions. This empty sequence caused the is_clearly_healthy function to loop infinitely because condition 4 requires at least one investigative operation.

Fix:

  • Noise Extraction: Updated app/nodes/extract_alert/extract.py prompt to explicitly state that informational states and health checks are NOT noise.
  • Planner Prompt Guidance: Updated app/nodes/plan_actions/build_prompt.py to ensure the agent MUST still query relevant monitoring platforms for verification when it identifies informational or healthy states.
  • Planner Code Guard: Added a code-level guard in app/nodes/plan_actions/node.py to fall back and force at least one verification action if the LLM returns an empty plan to prevent infinite insufficient_evidence loops.
  • Evidence Consistency: Fixed EKS evidence truthiness check in app/nodes/root_cause_diagnosis/evidence_checker.py to correctly evaluate via is not None.
  • Cleanup: Removed accidentally committed pr_body.md template.

GitHub logo fix: Database logic expansion for QA Edge Cases (Batch 2) #626

_build_database_directive() has been expanded exponentially to train the AI to parse red herrings, distinguish between dual fault symptoms versus single root causes, infer missing Storage metrics organically, ignore healthy oscillating traffic metrics, and trace WAL replication lags adequately.

GitHub logo fix: Database logic expansion for QA Edge Cases (Batch 3) #627

Resolves #606, resolves #607, resolves #608, resolves #609, resolves #610. Expands the _build_database_directive() function to correctly train the LLM to identify Compositional Faults (treating simultaneous CPU and Storage constraints as independent sources while filtering out connection bounds), infer replication lag from bare WAL metrics despite missing Replica metrics, accurately ignore historical maintenance distractions via timestamps, identify stale autoscaling recovery, and distinguish VACUUM-driven Checkpoint Storms.

I delivered the fix in three batched PRs. Each batch expanded the directive system with new training scenarios. The LLM learned to recognize healthy patterns, distinguish them from noise, and handle complex edge cases.

The key was batching. One massive PR would have been impossible to review. Three focused PRs made each change tractable and reviewable.

The Lesson

AI systems are only as good as their training data. When your AI misclassifies, do not blame the model. Blame the data. And then fix it. The directive expansion approach I used here is applicable to any AI system that makes classification decisions.


Story Six: The Float That Was Too Small to Exist

The Discovery

In OpenMythos, a research tool for linear time-invariant systems, I encountered a numerical bug that broke a mathematical guarantee.

The spectral radius ρ(A) must be less than 1 for system stability. The code computed it using exp(log_dt + log_A). After large gradient steps, log_dt + log_A could drop below -20. The exponential of -20 is approximately 2.06e-9.

Here is the problem. Float32 machine epsilon is approximately 1.19e-7. When you take the outer exponential of a number smaller than machine epsilon, the result rounds to exactly 1.0. Not approximately 1.0. Exactly 1.0.

This broke the ρ(A) < 1 guarantee. The system appeared stable when it was not. In research code, this kind of silent failure can invalidate months of work.

The Fix

GitHub logo Fix float32 underflow in LTIInjection.get_A() breaking ρ(A) < 1 guarantee #1

After sufficiently large gradient steps, log_dt + log_A can be driven below -20, causing exp(-20) ≈ 2.06e-9 — smaller than float32 machine epsilon (≈ 1.19e-7) — so the outer exp(-2.06e-9) rounds to exactly 1.0, silently invalidating the spectral radius stability guarantee.

Change

  • LTIInjection.get_A(): tighten inner clamp lower bound from -20-14

At -14: exp(-14) ≈ 8.3e-7, which sits above the float32 ULP threshold at 1.0 (~5.96e-8), ensuring exp(-exp(x)) is always representable as strictly less than 1.0 in float32.

# Before — exp(-20) ≈ 2.06e-9 < float32_eps, outer exp rounds to 1.0
return torch.exp(-torch.exp((self.log_dt + self.log_A).clamp(-20, 20)))

# After — exp(-14) ≈ 8.3e-7 > ULP threshold, A < 1.0 holds in float32
return torch.exp(-torch.exp((self.log_dt + self.log_A).clamp(-14, 20)))

Enter fullscreen mode Exit fullscreen mode

The upper bound (20) is unchanged; it guards against the opposite extreme (overflow → A ≈ 0), which is not problematic for stability.

I implemented numerically stable computation using appropriate scaling and clamping. The fix prevents the intermediate result from falling below the representable range of float32.

The Lesson

Floating point arithmetic is a minefield. Every comparison, every exponentiation, every accumulation is a potential bug. When you are doing numerical computing, you need to think about precision at every step. The math might be correct on paper. The computer might still get it wrong.


The Tools That Made It Possible

I want to talk about the tools because they mattered enormously.

Antigravity Agentic IDE

This is not a regular code editor. It is an AI-native development environment that understands context across your entire codebase. I used it for:

  • Codebase exploration: Understanding repositories I had never seen before in minutes instead of hours
  • Bug diagnosis: Tracing error paths and identifying root causes with AI-assisted analysis
  • Fix generation: Drafting code changes that followed each project's conventions
  • Test verification: Running and interpreting test results across different environments

Google AI

The AI models behind Antigravity, powered by Google, were the engine that made everything else possible. They helped me find bugs I would have missed, understand codebases faster, and implement fixes with confidence.


What I Learned

After 373 merged pull requests, here are the lessons that stuck:

  • Security first. The most impactful fixes are often the simplest. Two lines of authorization logic can prevent a system takeover.

  • Question assumptions. Windows does support symlinks. The lock was not always acquired. The path was not always short enough. Every assumption is a potential bug.

  • Batch complex work. Three small PRs are better than one massive PR. Reviewers stay engaged. Mistakes get caught. Progress is visible.

  • Clean up responsibly. The finally block deserves the same attention as the try block. Resource cleanup is where silent failures happen.

  • Train your AI right. When AI systems misclassify, fix the training data. The model is not broken. Its education is incomplete.

  • Precision matters. Floating point arithmetic will betray you if you let it guard. Think about numerical stability in every calculation.


By the Numbers

Metric Count
Total merged pull requests 373
Repositories contributed to 6+
Security vulnerabilities patched 2
Cross-platform compatibility fixes 5
Race conditions resolved 1
AI classification accuracy improvements 4
Numerical stability fixes 1
Test coverage restorations 3
UI/UX fixes 1

Closing Thoughts

This journey has been one of the most rewarding experiences of my development career. Every bug I fixed made someone's software a little better. Every PR I merged taught me something new. Every community I joined welcomed my contributions.

Open source is not just about code. It is about showing up, doing the work, and making things better for everyone who comes after you.

To the maintainers who reviewed my PRs: thank you for your patience and your feedback.

To the users who reported the bugs: thank you for taking the time to write clear issue descriptions.

To DEV, Sentry, and Google AI: thank you for creating this challenge and for supporting the open source community.

I am Aniruddha Adak, and I am just getting started.


Connect with me on LinkedIn, follow me on X, or explore my code on GitHub.