A tiny missing check, a silent crash, and a denied permission that should have been safe. This is the story of how I fixed it.

About me and why this matters

I am Aniruddha Adak, a full stack developer from Kolkata, working across Next.js, React, TypeScript, Python and AI agent tooling. My GitHub profile is aniruddhaadak80 with over 238 accepted pull requests during Hacktoberfest and active contributions to projects like google-gemini/gemini-cli, openclaw/openclaw, topoteretes/cognee and NousResearch/hermes-agent.

Over the last two years I have been focusing on one thing, finding bugs that hide in plain sight, especially those that appear only on edge cases, cross platform setups and agent communication layers.

This post is my submission for DEV Summer Bug Smash 2026 in the Clear the Lineup track. It is also aiming for Best Use of Google AI.

What was the bug

The bug lived in NousResearch/hermes-agent, an open agent framework that connects AI models through the ACP protocol.

Inside the permission bridge, the function request_permission is expected to return an object that tells Hermes whether to allow or deny an action. But sometimes, when an ACP client sends an empty response, that function returns None.

The existing code trusted the result directly and accessed result.decision without checking. When result is None, this throws an AttributeError. The agent crashes instead of denying safely. For a permission system, crashing is worse than denying. It leaves the user hanging and can break long running sessions.

In simple words, the code trusted that it would always get an answer. When it got silence, it broke.

How I found it

I was working through open issues in hermes-agent while exploring how agent permissions work on different clients. I noticed issue #13449 which described unexpected crashes during permission approval. I traced the flow from agent/transports to the ACP callback and I saw there was no guard for None. I reproduced it locally by mocking request_permission to return None and the crash happened instantly.

The bug was small, but its impact was large. Permission checks should never throw. They should always fail safe.

Reproducing the issue

To reproduce, you connect via an ACP client that can send an empty response to permission requests. Then you trigger any tool that requires permission approval and you send an empty payload from the client. In the server logs you will see AttributeError: 'NoneType' object has no attribute 'decision'.

My reproduction script was simple and it showed the problem clearly.

async def mock_request_permission():
    return None

# old logic that crashes
result = await mock_request_permission()
decision = result.decision

Enter fullscreen mode Exit fullscreen mode

With the old code, this crashes immediately. With the new code, it safely denies.

The fix, technical deep dive

My merged PR is fix(permissions): handle None response from ACP request_permission in the hermes-agent repository. The PR link is https://github.com/NousResearch/hermes-agent/pull/13457 and it is merged.

What I changed

I added a guard clause right after the await. If the response is None, I return "deny" immediately. I added a dedicated unit test for this edge case and I kept the change minimal to avoid touching any other permission logic.

New logic looks like this

result = await request_permission(...)

if result is None:
    return "deny"

if result.decision == "allow":
    return "allow"
return "deny"

Enter fullscreen mode Exit fullscreen mode

This is a classic fail safe pattern. In security code, when you do not know what happened, you deny. This pattern is simple, it is readable, and it prevents a whole class of crashes.

Why this fix is correct

It does not change the happy path at all. It prevents a crash that could be triggered by any ACP client. It aligns with the principle of least privilege and it adds test coverage so it will not regress in future releases.

How I used Google Antigravity and Google AI

I built this fix using Antigravity, the agentic IDE by Google, and it changed how I debug. For codebase exploration I used Gemini 2.5 Pro inside Antigravity to map all places where request_permission is called and where its return value is used. It gave me a full call graph in seconds and saved hours of manual search.

For reproduction scaffolding I prompted Antigravity to write a minimal async mock that returns None for ACP permission and triggers the approval callback. Antigravity generated the repro script and the test harness. For edge case reasoning I asked Gemini to list what else could be None in that bridge. It suggested checking for missing fields inside the result as a future hardening step.

I treat Antigravity as a pair programmer that never gets tired of reading large repos. It reads the whole codebase, I make the final decision. For the Best Use of Google AI category, this workflow shows how Gemini in Antigravity can find a security relevant bug faster and make the fix safer with tests.

All my merged bug fix PRs, only merged

I have kept this table to only merged PRs and only bug related ones. No drafts, no closed unmerged, no docs typo fixes. This shows breadth and consistency.

All of these are merged and verified in production releases.

Testing and validation

I ran pytest tests/ -q locally and all tests passed. I added a new unit test that specifically covers the None case. I verified that existing permission tests still pass and I checked cross platform impact as per the contributing guide. No OS specific change was needed for this fix.

Impact of the fix

The impact is clear. For stability, there are no more crashes when ACP clients send empty responses. For security, the permission system now fails safe to deny. For developer experience, there is now clear behavior for agent builders using custom ACP clients. For reliability, long running hermes sessions no longer die on this edge case.

What I learned

Permission code should never trust external input. A single missing None check can break an entire agent session. Writing a reproduction script first makes the fix obvious. Using an agentic IDE like Antigravity helps you see the full picture across many files. Small focused PRs get merged faster than large ones.

If you are starting with open source, start with bugs like this. Small, focused, high impact. That is how you learn and how you win trust from maintainers.


Links

GitHub is https://github.com/aniruddhaadak80
Dev profile is https://dev.to/aniruddhadak
PR discussed is https://github.com/NousResearch/hermes-agent/pull/13457
Challenge page is https://dev.to/bugsmash