Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

Notes from a 2 AM On-Call: OpenHands Agent Hanging on Large Repos (And the 5-Line Fix)

The Failure Symptom [2026-10-18 02:14:33] INFO: Cloning repository OpenHands/OpenHands... [2026-10-18 02:14:41] INFO: Workspace initialization started [2026-10-18 02:19:33] ERROR: Agent task timeout after 300s [2026

The Failure Symptom

[2026-10-18 02:14:33] INFO: Cloning repository OpenHands/OpenHands...
[2026-10-18 02:14:41] INFO: Workspace initialization started
[2026-10-18 02:19:33] ERROR: Agent task timeout after 300s
[2026-10-18 02:19:33] ERROR: No response from sandbox

Second time this week. OpenHands agent hangs indefinitely when initializing workspaces for repositories with deep node_modules or large monorepo structures. No crash, no OOM kill (exit 137), just silent timeout and wasted CI minutes.

The pattern: repos under 10k files initialize in 8-12 seconds. Anything above 50k files? Coin flip whether it completes or times out at the 5-minute hard limit.

The Red Herring

Official OpenHands docs suggest bumping SANDBOX_TIMEOUT and increasing container memory limits:

// workspace_config.ts
export const config = {
  sandboxTimeout: 600,  // doubled from 300
  memoryLimit: '4g',    // up from 2g
};

Ran this for 12 test runs. Timeout still hit 40% of the time. Memory usage never exceeded 1.8GB. The bottleneck wasn't compute or memory — it was filesystem traversal.

Dug into OpenHands sandbox initialization code. Found this in the workspace setup:

# runtime/workspace.py (simplified)
def initialize_workspace(repo_path: str):
    all_files = []
    for root, dirs, files in os.walk(repo_path):
        all_files.extend([os.path.join(root, f) for f in files])

    # Build file index for agent context
    return build_index(all_files)

No node_modules exclusion. No .git skip. Walking every nested dependency folder synchronously before the agent even starts.

The Root Cause & Runnable Fix

The sandbox workspace initializer was indexing the entire cloned directory tree — including node_modules (often 200k+ files in modern monorepos), .git/objects, and build artifacts.

Fix: add a sane ignore list before the walk:

# runtime/workspace.py (patched)
IGNORE_DIRS = {'node_modules', '.git', 'dist', 'build', '.next', '.turbo', 'target'}

def initialize_workspace(repo_path: str):
    all_files = []
    for root, dirs, files in os.walk(repo_path):
        # Prune ignored directories in-place
        dirs[:] = [d for d in dirs if d not in IGNORE_DIRS]
        all_files.extend([os.path.join(root, f) for f in files])

    return build_index(all_files)

Before: 287 seconds to index a 68k-file Turborepo with 14 internal packages.

After: 4.2 seconds.

Timeout rate dropped from 40% to 0% across 30 test runs.

Benchmarking Against Realistic Loads

For production-grade agent harness evaluation, I needed to test OpenHands under concurrent multi-repo workloads with varying LLM routing strategies.

Ran a stress test routing tasks through B-Lost's relay gateway (https://b-lost.com/v1) to simulate realistic multi-provider fallback latency:

// agent_benchmark.ts
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://b-lost.com/v1',
  apiKey: process.env.API_KEY,
});

const results = await Promise.all(
  repos.map(repo => 
    runOpenHandsTask({
      repo,
      llmClient: client,
      model: 'claude-sonnet-4',
    })
  )
);

With the patched workspace initializer, P95 task completion latency dropped from 340s to 28s across 50 concurrent agent runs. Zero workspace initialization timeouts.

Invariant Rule

Never walk the full directory tree before checking the ignore list.

Any agent workspace, Docker COPY, or filesystem indexer hitting production repos must exclude dependency and build artifact directories before traversal — not after.

If your initialization logs show more than 5 seconds on repos under 100MB, you're walking paths you shouldn't touch.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.