Error Handling
The SDK surfaces two typed error classes for the most common failure modes. All other errors propagate as ConnectError instances.
Quickstart
Section titled “Quickstart”from githosted import Client, StaleHeadError, RepoBusyError
client = Client()repo = client.repo("my-project")
try: file = repo.read("config.json") repo.write( "config.json", new_content, "Update config", expected_head=file.head_sha, )except StaleHeadError as err: print(f"Branch moved to {err.actual_head}")except RepoBusyError as err: print(f"Repo busy: {err.operation}")Error Types
Section titled “Error Types”RepoBusyError
Section titled “RepoBusyError”Raised when another operation is actively mutating the repo. The repo service uses per-repo leasing — only one writer at a time.
| Property | Type | Description |
|---|---|---|
repo_id | str | Canonical repo ID (rp_ prefix) |
operation | str | What the current holder is doing |
Auto-retry: The SDK automatically retries RepoBusyError with exponential backoff (100ms base, 3 retries max) before surfacing the error to your code. If you see this error, all retries have been exhausted.
from githosted import is_repo_busy_error
try: repo.write("file.py", content, "update")except Exception as err: if is_repo_busy_error(err): # All 3 retries failed — the repo is under sustained write load print(f"Repo {err.repo_id} busy with: {err.operation}")StaleHeadError
Section titled “StaleHeadError”Raised when expected_head doesn’t match the current branch tip. This means another write landed between your read and write.
| Property | Type | Description |
|---|---|---|
repo_id | str | Canonical repo ID |
ref | str | Branch that was written to |
expected_head | str | The SHA you sent |
actual_head | str | The current branch tip |
Never auto-retried. You must decide how to handle the conflict — re-read and retry, merge, or abort.
from githosted import is_stale_head_error
try: repo.write( "file.py", content, "update", expected_head=previous_head_sha, )except Exception as err: if is_stale_head_error(err): # Re-read from actual_head and try again fresh = repo.read("file.py") # ... merge or retry with fresh.head_shaWire Contract
Section titled “Wire Contract”Both error types are backed by protobuf error detail messages attached to Connect errors:
| Connect Code | Error Detail | SDK Error Class |
|---|---|---|
Aborted | RepoBusyDetail | RepoBusyError |
FailedPrecondition | StaleHeadDetail | StaleHeadError |
The SDK parses these from the Connect error details field. It never infers error types from message strings.