Skip to content

fix: error handling — log instead of silently swallowing errors (11 bugs)#2881

Open
HUQIANTAO wants to merge 6 commits into
Hmbown:mainfrom
HUQIANTAO:fix/error-handling-bugs
Open

fix: error handling — log instead of silently swallowing errors (11 bugs)#2881
HUQIANTAO wants to merge 6 commits into
Hmbown:mainfrom
HUQIANTAO:fix/error-handling-bugs

Conversation

@HUQIANTAO
Copy link
Copy Markdown
Contributor

@HUQIANTAO HUQIANTAO commented Jun 7, 2026

Summary

Fixes 11 error handling bugs where errors were silently discarded via let _ =, Err(_), .ok(), or .to_string(), preventing users from diagnosing failures and masking data loss.

Bugs Fixed

Silent Error Discards

  1. persist_config errors discarded (app-server/lib.rs:882,896)

    • After ConfigSet/ConfigUnset, disk write failure returns success to the user. Change is lost on restart.
    • Fix: Log tracing::error! on persistence failure.
  2. Job store load error discarded (core/lib.rs:751)

    • Corrupted store silently starts with empty job list, losing all history.
    • Fix: Log tracing::warn! on load failure.
  3. Config parse failure returns None (config/lib.rs:1590)

    • toml::from_str().ok() makes "malformed config" indistinguishable from "no config file".
    • Fix: Log tracing::warn! with the parse error before returning None.
  4. MCP connect_all errors discarded (mcp.rs:2151,2189)

    • Failed server connections produce incomplete resource list with no indication.
    • Fix: Log tracing::warn! for each failed server.
  5. Error chain stripped in engine status (core/engine.rs:2221)

    • err.to_string() loses the anyhow error chain. Line 2234 already uses {err:#} correctly.
    • Fix: Use format!("{err:#}") for consistency.
  6. Tool audit log failures all discarded (tool_execution.rs:122-136)

    • Serialization, directory creation, file open, and write errors are all silently dropped.
    • Fix: Log each failure type with tracing::error!.
  7. Env var invalid values silently ignored (config/lib.rs:2519-2530)

    • DEEPSEEK_YOLO=TRUE (wrong case) or DEEPSEEK_TELEMETRY=maybe treated as unset.
    • Fix: Log tracing::warn! on parse failure.
  8. MCP config reload errors completely silent (mcp.rs:2011)

    • User edits MCP config expecting changes to take effect, but parse error is ignored.
    • Fix: Log tracing::warn! instead of let _ =.

Logic Errors

  1. expect() on sub-agent runtime (core/engine.rs:1713)

    • Panics if sub-agents enabled but no API client configured. Uses let-else with return which causes compilation errors.
    • Fix: Use if let Some with fallback to basic tool set.
  2. expect() on goal objective (core/engine.rs:2536)

    • Fragile check-then-expect pattern. Refactored code changes semantics when goal is inactive.
    • Fix: Use state.is_active().then(|| objective.to_string()) to preserve original behavior.
  3. Windows stderr redirect error discarded (runtime_log.rs:179)

    • Fix: Log tracing::warn! on redirect failure.

1. Fix swallowed persist_config errors (app-server/lib.rs:882,896)
   - Log errors when config persistence fails after set/unset
   - Users previously got success response even when disk write failed

2. Fix swallowed job store load error (core/lib.rs:751)
   - Add warning log when job store fails to load at startup
   - Previously silently started with empty job list on corruption

3. Fix silent config parse failures (config/lib.rs:1590)
   - Log warning when project config TOML is malformed
   - Previously returned None indistinguishable from 'no config file'

4. Fix MCP connect_all errors swallowed (mcp.rs:2151,2189)
   - Log warnings for each server that fails to connect
   - Previously returned incomplete resource list with no indication

5. Fix error context stripped in engine status (core/engine.rs:2223)
   - Use {err:#} format to include full error chain
   - Was inconsistent with line 2234 which already used {err:#}

6. Fix tool audit log failures silently dropped (tool_execution.rs:122-136)
   - Log each failure: serialization, directory creation, file open, write
   - Previously silently dropped all errors for security audit trail

7. Fix Err(_) arms discarding error info (runtime_log.rs:179, runtime_threads.rs:828)
   - Log stderr redirect failures on Windows
   - Log poisoned mutex in pending_approvals

8. Fix env var parsing errors silently ignored (config/lib.rs:2519-2530)
   - Warn when DEEPSEEK_TELEMETRY, DEEPSEEK_YOLO, DEEPSEEK_HTTP_HEADERS
     have invalid values instead of silently treating as unset

9. Fix MCP config reload errors swallowed (mcp.rs:2011)
   - Log config reload errors instead of complete silence

10. Fix .expect() on sub-agent runtime (core/engine.rs:1715)
    - Gracefully fall back to basic tool set when API client missing
    - Previously panicked if subagents enabled but no client configured

11. Fix .expect() on goal objective (core/engine.rs:2543)
    - Use safe if-let pattern instead of check+expect
    - Prevents panic if refactoring changes control flow
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 7, 2026

Thanks @HUQIANTAO for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves error handling and observability across several crates by replacing silent error discards with explicit logging (using tracing::warn! and tracing::error!). However, the changes in crates/tui/src/core/engine.rs introduce two issues: a compilation error in the sub-agent fallback logic due to an invalid return in a let-else block, and a subtle logic change in goal_objective_for_prompt that alters the fallback behavior when the state is inactive. Addressing these issues with the suggested refactorings will ensure the code compiles and maintains its original behavior.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/tui/src/core/engine.rs Outdated
Comment on lines 1711 to 1722
let Some(subagent_runtime) = runtime else {
tracing::warn!("Sub-agents enabled but no API client available, falling back to basic tool set");
return Some(builder.build(tool_context));
};
Some(
builder
.with_subagent_tools(
self.subagent_manager.clone(),
runtime.expect("sub-agent runtime should exist with active client"),
subagent_runtime,
)
.build(tool_context),
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This block introduces a compilation error. handle_send_message is an async fn that returns (), but the return Some(builder.build(tool_context)) statement inside the let-else block attempts to return Some(ToolRegistry). Additionally, using let-else here forces a diverging control flow (like return), which is not what you want since you want to fall back to the basic tool set and continue the function. Using a standard if let Some expression allows you to cleanly assign the fallback registry to tool_registry and continue execution without compilation errors.

Suggested change
let Some(subagent_runtime) = runtime else {
tracing::warn!("Sub-agents enabled but no API client available, falling back to basic tool set");
return Some(builder.build(tool_context));
};
Some(
builder
.with_subagent_tools(
self.subagent_manager.clone(),
runtime.expect("sub-agent runtime should exist with active client"),
subagent_runtime,
)
.build(tool_context),
)
if let Some(subagent_runtime) = runtime {
Some(
builder
.with_subagent_tools(
self.subagent_manager.clone(),
subagent_runtime,
)
.build(tool_context),
)
} else {
tracing::warn!("Sub-agents enabled but no API client available, falling back to basic tool set");
Some(builder.build(tool_context))
}

Comment on lines +2539 to 2543
if let Some(objective) = state.objective() {
if state.is_active() {
return Some(objective.to_string());
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This refactoring introduces a subtle logic change. In the original code, if state.objective() was Some but state.is_active() was false, the function returned None immediately, bypassing the fallback to normalized_goal_objective(configured_goal). With the new if let Some structure, if state.is_active() is false, the function falls through the match block and returns normalized_goal_objective(configured_goal). To preserve the exact original behavior safely without using expect, you can return state.is_active().then(...) directly when state.objective() is Some.

            if let Some(objective) = state.objective() {
                return state.is_active().then(|| objective.to_string());
            }

1. Replace let-else with if-let-Some to avoid compilation error
   - let-else with return would return from the entire function
   - if-let-Some correctly assigns to tool_registry and continues

2. Preserve original goal_objective_for_prompt behavior
   - Return None (not fallback) when objective exists but goal is inactive
   - Use state.is_active().then() to match original semantics
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@HUQIANTAO HUQIANTAO changed the title fix: error handling bugs - log instead of silently swallowing errors (11 bugs) fix: error handling — log instead of silently swallowing errors (11 bugs) Jun 7, 2026
- Add tracing.workspace = true to crates/core/Cargo.toml
  (required for tracing::warn! in lib.rs:752)
- Apply cargo fmt formatting to engine.rs, mcp.rs, tool_execution.rs, config/lib.rs
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Required for tracing::error! in persist_config error handling.
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUQIANTAO has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant