stablyai/orca · error
normalizeGitErrorMessage(error, 'upstream')
Error message
normalizeGitErrorMessage(error, 'upstream')
What it means
Thrown by getUpstreamStatus after the underlying git command (rev-list/log for ahead-behind counting) fails for any reason OTHER than a clearly-recognized 'no upstream configured' signal. The raw execFile error is passed through normalizeGitErrorMessage so that stderr preambles and local filesystem paths are stripped before the error crosses the IPC boundary into the renderer. It represents a genuine git failure (auth, corruption, 'not a git repository', sparse-checkout) that the user must act on, not an expected empty-upstream state.
Source
Thrown at src/main/git/upstream.ts:71
(args) => gitExecFileAsync(args, gitExecOptions(worktreePath, options)),
(upstreamName) => getBehindCommitsArePatchEquivalent(worktreePath, upstreamName, options)
)
} catch (error) {
// Why: we only swallow clearly-no-upstream signals — that's an expected
// state, not a failure. Other errors (auth, corruption, "not a git
// repository", sparse-checkout) should surface to the user so they can
// act on them. The shared isNoUpstreamError helper intentionally omits
// broad phrases like "no such branch" to avoid masking real errors.
if (isNoUpstreamError(error)) {
return {
hasUpstream: false,
ahead: 0,
behind: 0
}
}
// Why: parity with gitPush/gitPull/gitFetch — normalize before crossing
// the IPC boundary so renderers don't see execFile stderr preambles or local paths.
throw new Error(normalizeGitErrorMessage(error, 'upstream'))
}
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Read the normalized message text — it preserves the git failure category (auth/corruption/not-a-repo) which tells you the real cause.
- From a terminal in the same worktree path, run the equivalent probe by hand (e.g. `git rev-list --left-right --count HEAD...@{u}`) to reproduce and see git's full stderr.
- If auth-related, refresh credentials (`gh auth login` for GitHub, or the configured credential helper) and retry.
- If 'not a git repository' or sparse-checkout related, verify the worktree path still exists and `git worktree list` is consistent; re-create the worktree if its admin files are gone.
- Clear a stale `index.lock` only if no other git process is running.
Example fix
// before: renderer trusts hasUpstream blindly and crashes on throw
const status = await getUpstreamStatus(path)
if (!status.hasUpstream) publish()
// after: surface the normalized git failure to the user
try {
const status = await getUpstreamStatus(path)
if (!status.hasUpstream) publish()
} catch (err) {
toast.error(`Could not read upstream status: ${messageFromError(err)}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-call validation can predict a git corruption / auth failure.
// Validate the path is a non-empty string and a git repo before the call to
// narrow the failure space:
import { existsSync } from 'node:fs'
function assertWorktreePath(path: string) {
if (!path || typeof path !== 'string') throw new Error('worktree path required')
if (!existsSync(path)) throw new Error(`worktree path missing: ${path}`)
} Type guard
function isGitFailureWithMessage(err: unknown): err is Error {
return err instanceof Error && err.message.length > 0
} Try / catch
try {
const status = await getUpstreamStatus(worktreePath, pushTarget, options)
// use status
} catch (err) {
// message is already normalized — show to user, do not log raw stderr
toast.error(`Upstream check failed: ${(err as Error).message}`)
} Prevention
- Never swallow this throw silently — it carries a real git failure category.
- Do not re-run the exact same probe in a tight loop; address the underlying git state first.
- Keep credentials fresh so implicit fetches during the probe do not auth-fail.
When it happens
Trigger: Calling getUpstreamStatus on a worktree whose .git metadata is corrupted; a sparse-checkout reconfigure that broke ref reads; a remote URL with expired/revoked credentials where the ahead-behind probe triggers a fetch; running against a directory that is no longer a git repository after a botched move; a git binary crash or lock contention (index.lock held).
Common situations: Worktree was moved or its administrative files deleted out-of-band; credentials helper returned an auth error during an implicit fetch; a concurrent git process holds index.lock; the repo lives on a network mount that dropped; sparse-checkout patterns reference paths git can't resolve.
Related errors
- Branch status unavailable
- ${label} must be a full git object id
- Remote connection dropped. Click Reconnect on the SSH target
- No git provider for connection "${args.connectionId}"
- Commit message is required
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/fcdab59147af6256.
Report an issue: GitHub.