Skip to content

Error Handling

The SDK surfaces two typed error classes for the most common failure modes. All other errors propagate as ConnectError instances.

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}")

Raised when another operation is actively mutating the repo. The repo service uses per-repo leasing — only one writer at a time.

PropertyTypeDescription
repo_idstrCanonical repo ID (rp_ prefix)
operationstrWhat 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}")

Raised when expected_head doesn’t match the current branch tip. This means another write landed between your read and write.

PropertyTypeDescription
repo_idstrCanonical repo ID
refstrBranch that was written to
expected_headstrThe SHA you sent
actual_headstrThe 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_sha

Both error types are backed by protobuf error detail messages attached to Connect errors:

Connect CodeError DetailSDK Error Class
AbortedRepoBusyDetailRepoBusyError
FailedPreconditionStaleHeadDetailStaleHeadError

The SDK parses these from the Connect error details field. It never infers error types from message strings.