remotion-dev/remotion · error · Error
Could not read ${owner}/${repo}: ${await getResponseError(tr
Error message
Could not read ${owner}/${repo}: ${await getResponseError(treeResponse)} What it means
loadGitHubRepository calls GET https://api.github.com/repos/{owner}/{repo}/git/trees/HEAD?recursive=1 without authentication and throws on any non-2xx response, appending GitHub's own error message from the JSON body (or the status text). Common statuses: 404 for a missing or private repository, 403 for exceeding GitHub's anonymous rate limit (60 requests/hour per IP), and 5xx for GitHub incidents.
Source
Thrown at packages/browser-studio/src/load-github-repository.ts:148
export const loadGitHubRepository = async ({
onProgress,
repoUrl,
signal,
}: {
onProgress?: (progress: LoadGitHubRepositoryProgress) => void;
repoUrl: string;
signal?: AbortSignal;
}): Promise<VirtualProject> => {
const {owner, repo} = parseGitHubRepositoryUrl(repoUrl);
onProgress?.({phase: 'reading-repository'});
const treeResponse = await fetch(
`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/trees/HEAD?recursive=1`,
{signal},
);
if (!treeResponse.ok) {
throw new Error(
`Could not read ${owner}/${repo}: ${await getResponseError(treeResponse)}`,
);
}
const tree = (await treeResponse.json()) as GitHubTreeResponse;
if (!tree.tree || !tree.sha) {
throw new Error(
`Could not read ${owner}/${repo}: ${tree.message ?? 'GitHub returned an invalid file tree.'}`,
);
}
const treeSha = tree.sha;
if (tree.truncated) {
throw new Error(
`${owner}/${repo} has too many files for Browser Studio to load.`,
);
}View on GitHub (pinned to 10db9de073)
Solutions
- Verify owner/repo spelling and that the repository is public
- If the message mentions the rate limit, wait for GitHub's anonymous quota (60 requests/hour per IP) to reset
- Retry after a few minutes for transient GitHub 5xx errors
- Check https://www.githubstatus.com/ during suspected API incidents
Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`);
if (res.status === 404) throw new Error('Repository does not exist or is private');
if (res.status === 403 || res.status === 429) throw new Error('GitHub anonymous rate limit reached - wait before retrying');
if (!res.ok) throw new Error(`GitHub API returned ${res.status}`); Try / catch
const backoff = (ms: number) => new Promise((r) => setTimeout(r, ms));
try {
await loadGitHubRepository({repoUrl});
} catch (e) {
const msg = String((e as Error).message);
if (msg.includes('Not Found')) throw new Error('Repo is private or does not exist - check owner/repo');
if (/rate limit/i.test(msg)) await backoff(60_000); // anonymous quota window, then retry
else throw e;
} Prevention
- Verify the repo is public and the owner/repo spelling is correct before loading
- Cache or throttle loadGitHubRepository calls to conserve the 60 req/h anonymous GitHub API quota per IP
- Treat 403 with 'rate limit' in the message differently from 404 - one waits, the other is a typo
When it happens
Trigger: Loading a repo URL that does not exist or is private (404 Not Found); loading many repos in quick succession from one IP until the anonymous quota is exhausted (403 rate limit); GitHub API incidents returning 5xx.
Common situations: Typos in owner/repo; private repositories (the API is unauthenticated so they are invisible); shared NAT/office networks where the per-IP anonymous quota is consumed by others; embedding a Browser Studio link that many users open at once.
Related errors
- Could not read ${owner}/${repo}: ${tree.message ?? 'GitHub r
- Could not download ${file.path}: ${await getResponseError(re
- Timed out downloading remote asset
- Could not fetch remote asset. The URL may not allow cross-or
- Could not download remote asset: ${response.status}
AI-assisted analysis of remotion-dev/remotion@10db9de073 (2026-08-22).
Data as JSON: /api/errors/6c134a04b643b71c.
Report an issue: GitHub.