Error Handling
The SDK surfaces two typed error classes for the most common failure modes. All other errors propagate as standard ConnectError instances.
Quickstart
Section titled “Quickstart”import { Client, StaleHeadError, RepoBusyError } from "@githosted/sdk";
const client = new Client();const repo = client.repo("my-project");
try { const file = await repo.read("config.json"); await repo.write("config.json", newContent, { message: "Update config", expectedHead: file.headSha, });} catch (err) { if (err instanceof StaleHeadError) { console.log(`Branch moved to ${err.actualHead}`); } else if (err instanceof RepoBusyError) { console.log(`Repo busy: ${err.operation}`); }}Error Types
Section titled “Error Types”RepoBusyError
Section titled “RepoBusyError”Thrown when another operation is actively mutating the repo. The repo service uses per-repo leasing — only one writer at a time.
| Property | Type | Description |
|---|---|---|
repoId | string | Canonical repo ID (rp_ prefix) |
operation | string | 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.
import { isRepoBusyError } from "@githosted/sdk";
try { await repo.write("file.ts", content, { message: "update" });} catch (err) { if (isRepoBusyError(err)) { // All 3 retries failed — the repo is under sustained write load console.log(`Repo ${err.repoId} busy with: ${err.operation}`); }}StaleHeadError
Section titled “StaleHeadError”Thrown when expectedHead doesn’t match the current branch tip. This means another write landed between your read and write.
| Property | Type | Description |
|---|---|---|
repoId | string | Canonical repo ID |
ref | string | Branch that was written to |
expectedHead | string | The SHA you sent |
actualHead | string | The current branch tip |
Never auto-retried. You must decide how to handle the conflict — re-read and retry, merge, or abort.
import { isStaleHeadError } from "@githosted/sdk";
try { await repo.write("file.ts", content, { message: "update", expectedHead: previousHeadSha, });} catch (err) { if (isStaleHeadError(err)) { // Re-read from actualHead and try again const fresh = await repo.read("file.ts"); // ... merge or retry with fresh.headSha }}Wire 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.