tldraw/tldraw · error · Error

gh api failed for PR #${pr}: ${err.stderr ?? err}

Error message

gh api failed for PR #${pr}: ${err.stderr ?? err}

What it means

Thrown by prState in dns-check.ts when the gh CLI call to fetch a PR's state fails with an error whose stderr does not contain 'HTTP 404'. A 404 is intentionally treated as 'closed' (deleted PR); any other failure is re-thrown so a broken gh auth cannot misclassify an open PR as closed.

Source

Thrown at internal/scripts/cloudflare/dns-check.ts:42

	const data = (await res.json()) as { success: boolean; errors: unknown; result: T }
	if (!data.success) throw new Error(`GET ${endpoint}: ${JSON.stringify(data.errors)}`)
	return data.result
}

const prStateCache = new Map<string, string>()
function prState(pr: string): string {
	let state = prStateCache.get(pr)
	if (!state) {
		try {
			state = execFileSync('gh', ['api', `repos/tldraw/tldraw/pulls/${pr}`, '--jq', '.state'], {
				encoding: 'utf-8',
				stdio: ['ignore', 'pipe', 'pipe'],
			}).trim()
		} catch (err: any) {
			if (String(err.stderr).includes('HTTP 404')) {
				state = 'closed'
			} else {
				throw new Error(`gh api failed for PR #${pr}: ${err.stderr ?? err}`)
			}
		}
		prStateCache.set(pr, state)
	}
	return state
}

interface DnsRecord {
	type: string
	name: string
	content: string
	proxied: boolean
}

async function main() {
	const zones = await cfApi<{ id: string }[]>(`/zones?name=${zoneName}`)
	if (!zones[0]) throw new Error(`zone not found: ${zoneName}`)
	const zoneId = zones[0].id

View on GitHub (pinned to b31086b447)

Solutions

  1. Run 'gh auth status' and 'gh auth login' to ensure the CLI is authenticated for tldraw/tldraw.
  2. Read the interpolated stderr to identify the exact gh failure (rate limit, auth, network).
  3. If rate-limited, wait and rerun; the prStateCache means reruns skip already-resolved PRs.
  4. Verify the PR number parsed from the DNS record name is a valid integer (the regex /^pr-(\d+)-/ should guarantee this).

Example fix

// before
//   gh api failed for PR #123: HTTP 401 -- bad credentials
//
// after
//   gh auth login   # authenticate with tldraw/tldraw access
//   yarn tsx internal/scripts/cloudflare/dns-check.ts tldraw.com
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure gh is authed before running the script
import { execFileSync } from 'child_process'
function ghIsAuthed(): boolean {
  try {
    execFileSync('gh', ['auth', 'status'], { stdio: ['ignore', 'pipe', 'pipe'] })
    return true
  } catch {
    return false
  }
}
// if (!ghIsAuthed()) { console.error('run: gh auth login'); process.exit(1) }

Type guard

null

Try / catch

try {
  prState(prNum)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('gh api failed for PR')) {
    // check auth, rate limit; fail safe (do NOT treat as closed)
  }
  throw e
}

Prevention

When it happens

Trigger: The dns-check script resolves each pr-NNNN-* DNS record to a PR number and calls gh api repos/tldraw/tldraw/pulls/NNN; if gh exits non-zero for any reason other than a 404 (auth failure, network error, rate limit, 500), this throws.

Common situations: gh CLI is not authenticated (gh auth login not run / token expired); GH_TOKEN has no scope for tldraw/tldraw; GitHub API rate limit; transient network failure; the PR number was malformed from the record name.

Related errors


AI-assisted analysis of tldraw/tldraw@b31086b447 (2026-08-12). Data as JSON: /api/errors/915a58cf5734df3a. Report an issue: GitHub.