-
Notifications
You must be signed in to change notification settings - Fork 36
fix: Add error handling to git operations in Claude Code runner #378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Wrap git clone, fetch, checkout, and reset operations in try-catch blocks to prevent session failures when git operations encounter errors. Failed git operations now log warnings and allow sessions to continue gracefully. This improves resilience when: - Repository URLs are invalid or unreachable - Network issues occur during clone/fetch - Branch references don't exist - Authentication fails for specific repos in multi-repo sessions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This comment has been minimized.
This comment has been minimized.
Address code review feedback by: - Moving git identity configuration to only run after successful git operations - Adding ignore_errors=True to all git config commands for robustness - Checking repo directory existence before configuring git identity - Eliminating duplicate git config code This prevents attempting to configure git on non-existent repositories when clone operations fail, and makes git config operations more resilient. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Claude Code ReviewSummaryThis PR improves error resilience in the Claude Code runner by wrapping git operations (clone, fetch, checkout, reset) in try-catch blocks. The changes allow sessions to continue gracefully when individual git operations fail, which is particularly valuable in multi-repo scenarios. The implementation follows existing error handling patterns in the codebase and adds helpful user feedback via log messages. Overall Assessment: ✅ Approve with minor recommendations The core changes are solid and align with the project's resilience goals. A few areas could be strengthened around error specificity, testing, and cleanup handling. Issues by Severity🟡 Major Issues1. Overly Broad Exception Handling
2. Missing Test Coverage
3. Inconsistent Cleanup After Failed Clone
🔵 Minor Issues4. Git Config Error Handling Could Be More Selective
5. Documentation Addition Lacks Integration Context
6. Error Messages Could Include More Context
Positive Highlights✅ Follows Existing Patterns: Error handling style (logging.warning + send_log + continue/return) is consistent with existing code (lines 190-197, 324-326, 1046-1047) ✅ Improved User Experience: User-facing messages ( ✅ Multi-Repo Resilience: Particularly valuable for multi-repo sessions where one bad repo shouldn't block others ✅ Workspace Reuse Logic Preserved: Correctly maintains the reuse_workspace flag behavior and doesn't interfere with continuation sessions ✅ Defensive Existence Checks: Added ✅ Minimal Code Churn: Changes are surgical and focused, reducing regression risk RecommendationsPriority Order:
Merge Decision:
Additional Context:
Consider running these tools to ensure style consistency: cd components/runners/claude-code-runner
black wrapper.py
isort wrapper.py
flake8 wrapper.py |
…eptions and cleanup Address all major issues from PR ambient-code#378 review: 1. Replace broad Exception handling with specific types - Changed `except Exception` to `except (RuntimeError, OSError)` for all git operations - Applied to clone, fetch, checkout, and reset operations (6 locations) - Allows unexpected errors to propagate while catching subprocess/IO failures 2. Add explicit cleanup after failed clones - Added `shutil.rmtree(repo_dir, ignore_errors=True)` in all clone exception handlers - Prevents partial clones in inconsistent state - Logs cleanup actions for observability 3. Improve error messages with exception context - All error messages now include exception type: `({type(e).__name__})` - Provides better debugging information 4. Add logging for git config failures - Updated `_run_cmd` to log warnings when `ignore_errors=True` - Prevents silent failures for non-critical git config operations 5. Add comprehensive test coverage - Created 6 unit tests (all passing) for error handling scenarios - Tests verify: graceful degradation, cleanup, specific exception types - Added testing guide with manual test scenarios and integration tests Changes: - wrapper.py: Improved error handling in git operations - test_git_error_handling_simple.py: Unit tests for error scenarios - GIT_ERROR_HANDLING_TESTING.md: Testing strategy documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Claude Code ReviewSummaryThis PR adds error handling to git operations in the Claude Code runner to prevent session failures when repositories are inaccessible. The implementation gracefully degrades by logging warnings and continuing execution rather than crashing. The changes include specific exception handling (RuntimeError, OSError), cleanup of partial clones, improved error messages, and comprehensive test coverage. Overall Assessment: ✅ Approve with minor recommendations The core improvements are solid and address a real reliability issue. The error handling is appropriately scoped, tests provide good coverage, and the graceful degradation approach is sound. Issues by Severity🟡 Major Issues1. Catch block scope may be too narrow in git reset operations (wrapper.py:859-867) The try-catch only wraps the git operations but not the git config operations that follow (lines 873-875). If git config fails and Location: try:
await self._run_cmd(["git", "remote", "set-url", ...], ignore_errors=True)
await self._run_cmd(["git", "fetch", ...])
await self._run_cmd(["git", "checkout", ...])
await self._run_cmd(["git", "reset", ...])
except (RuntimeError, OSError) as e:
# handle error
# Git config operations OUTSIDE try-catch (lines 873-875)
if repo_dir.exists():
await self._run_cmd(["git", "config", ...], ignore_errors=True) # If ignore_errors doesn't work?Recommendation: Consider wrapping git config in a separate try-catch or verify that 2. Missing test coverage for single-repo legacy flow (wrapper.py:903-920) The tests in Recommendation: Add at least one test case for the single-repo flow to ensure parity: @pytest.mark.asyncio
async def test_single_repo_clone_failure_does_not_raise(self):
"""Test that single-repo clone failures don't raise exceptions"""
temp_workspace = Path(tempfile.mkdtemp())
try:
context = MockRunnerContext(workspace_path=str(temp_workspace))
context._env = {
'INPUT_REPO_URL': 'https://github.com/test/repo.git',
'INPUT_BRANCH': 'main'
}
# ... rest of test3. Broad catch in multi-repo outer block may mask new errors (wrapper.py:884-887) The outer except Exception as e:
logging.error(f"Failed to prepare multi-repo workspace: {e}")
await self._send_log(f"Workspace preparation failed: {e}")
returnWhy this matters: If someone adds code here that has a typo (e.g., Recommendation: Change to 🔵 Minor Issues4. Inconsistent error message format (wrapper.py:841, 866, 915) Error messages vary slightly:
Recommendation: Standardize format to always include context (repo name/path), exception type, and error message. 5. Test utility code duplicated across test classes The test file has repeated setup code in multiple test methods:
Recommendation: Extract common setup into a pytest fixture: @pytest.fixture
def mock_adapter_with_repo():
temp_workspace = Path(tempfile.mkdtemp())
context = MockRunnerContext(workspace_path=str(temp_workspace))
context._env = {
'REPOS_JSON': '[{"name": "test-repo", "input": {"url": "https://github.com/test/repo.git", "branch": "main"}}]'
}
adapter = ClaudeCodeAdapter()
adapter.context = context
adapter.shell = MagicMock()
adapter.shell._send_message = AsyncMock()
yield adapter, temp_workspace
shutil.rmtree(temp_workspace, ignore_errors=True)6. Test assertion could be more specific (wrapper.py:79, 170, 194) Tests use # If we got here without raising, the test passes
assert TrueRecommendation: Add assertions that verify logging was called with expected warning messages: with patch('logging.warning') as mock_warning:
await adapter._prepare_workspace()
mock_warning.assert_called()
assert 'Failed to clone' in str(mock_warning.call_args)7. New system prompt addition not mentioned in PR description (wrapper.py:2000-2006) The PR adds a section about "External Service Integrations" to the workspace context prompt. This is a good addition but wasn't mentioned in the PR description. # External service integrations
prompt += "## External Service Integrations\n"
prompt += "When you need to interact with external services (JIRA, GitLab, GitHub, etc.), check if the relevant environment variables are available.\n\n"Recommendation: Either:
Positive Highlights✅ Excellent error handling pattern - Using specific exception types (RuntimeError, OSError) instead of broad Exception catching is exactly right per Python best practices ✅ Proper cleanup - Explicitly removing partial clones prevents inconsistent state ✅ Good observability - Error messages include exception types and context for debugging ✅ Test coverage - The test file covers the key scenarios (clone failure, partial cleanup, exception types) ✅ Consistent with Python standards - Follows the project's Python configuration (pyproject.toml) and testing patterns ✅ Graceful degradation - The continue-on-error approach is appropriate for multi-repo scenarios where one failed repo shouldn't kill the entire session RecommendationsHigh Priority
Medium Priority
Low Priority
Nice to Have
Code Quality Checklist✅ Error handling - Proper, specific exception types Final VerdictThis is a solid improvement to system reliability. The error handling approach is correct and the implementation is clean. The test coverage is good for the multi-repo path. Address the major issues (test coverage gap, outer exception scope) and this is ready to merge. Recommended Action: ✅ Approve with requested changes |
|
hey @aegeiger can you show me what this looks like when it happens? How often? How much time does it save when it catches something? |
|
Initially it was meant to address a concern of @sallyom that it's hard to debug when a failure to clone happens, for instance if the user tries to clone a repo from a private gitlab we don't have access to. But more broadly, I think her point was right, that a failure to clone shouldn't result in a failed session. |
Wrap git clone, fetch, checkout, and reset operations in try-catch blocks to prevent session failures when git operations encounter errors. Failed git operations now log warnings and allow sessions to continue gracefully.
This improves resilience when:
🤖 Generated with Claude Code