Hmbown/CodeWhale · error

search remains available

Error message

search remains available

What it means

A `.expect("search remains available")` panic: the tool_search tool failed to execute when the test verifies it stays reachable after other tools are evicted/deferred. tool_search is supposed to remain hydrated at all times so the model can rediscover deferred tools; its failure breaks that guarantee.

Solutions

  1. Inspect the Err from the failing call to see whether the tool is missing or execution failed.
  2. Ensure tool_search is always kept eager/warm and never counted against the deferred cache cap.
  3. Re-run with the warm list including TOOL_SEARCH_NAME to confirm eviction is the cause.
  4. Check that surface.hydrate("Web") failing afterwards is intended and unrelated to search availability.
Defensive patterns

Strategy: validation

Validate before calling

// Before executing, ensure tool_search is warm/eager on the surface
let warm = surface.warm_names();
assert!(warm.iter().any(|n| n == TOOL_SEARCH_NAME), "tool_search was evicted or never warmed");

Try / catch

if let Err(e) = execute_surface_tool(&registry, &mut surface, TOOL_SEARCH_NAME, &args).await {
    panic!("search must remain available after eviction changes: {e}");
}

Prevention

When it happens

Trigger: execute_surface_tool(&registry, &mut surface, TOOL_SEARCH_NAME, json!({"query":"web","match":"regex"})) returns Err in crates/tui/src/tools/subagent/tests.rs:8031, typically because the surface treated tool_search as deferable and evicted it, or its execution errored after hydration changes.

Common situations: Tightening the deferred-tool LRU so tool_search itself is evicted; changing SubAgentToolSurface::new to warm only a fixed list that omits tool_search; renaming TOOL_SEARCH_NAME.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/d07daae4d295c257. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/tests.rs:8031

    runtime.worker_profile.denied_tools.push("Web".to_string());
    let registry = SubAgentToolRegistry::new(
        runtime,
        FleetRole::Scout,
        None,
        crate::tools::todo::new_shared_todo_list(),
        crate::tools::plan::new_shared_plan_state(),
    );
    let catalog = registry.deferred_catalog_for_model(&FleetRole::Scout);
    let mut surface = SubAgentToolSurface::new(catalog, &["Web".to_string()]);
    assert!(!model_tool_names(model_request_tools(&mut surface)).contains("Web"));
    let searched = execute_surface_tool(
        &registry,
        &mut surface,
        TOOL_SEARCH_NAME,
        json!({"query": "web", "match": "regex"}),
    )
    .await
    .expect("search remains available");
    assert!(!searched.contains("\"tool_name\":\"Web\""));
    assert!(surface.hydrate("Web").is_err());
}

fn synthetic_deferred_tool(name: &str, description_bytes: usize) -> Tool {
    Tool {
        tool_type: Some("function".to_string()),
        name: name.to_string(),
        description: "x".repeat(description_bytes),
        input_schema: json!({"type": "object", "properties": {}}),
        allowed_callers: None,
        defer_loading: Some(true),
        input_examples: None,
        strict: None,
        cache_control: None,
    }
}

View on GitHub (pinned to 73e0f67d83)