gildas-lormeau/SingleFile · error · Error
responseData.message
Error message
responseData.message
What it means
createContent throws an Error whose message is the GitHub API's `message` field from the JSON response body when the HTTP status is >= 400. This surfaces GitHub's own error text (e.g. "Bad credentials", "Not Found", "name already exists on the same branch", "API rate limit exceeded") directly to the caller.
Source
Thrown at src/lib/github/github.js:134
return responseData;
} else if (filenameConflictAction == CONFLICT_ACTION_PROMPT) {
if (prompt) {
path = await prompt(path);
if (path) {
return await createContent({ path, content, message });
} else {
return responseData;
}
} else {
options.filenameConflictAction = CONFLICT_ACTION_UNIQUIFY;
return await createContent({ path, content, message });
}
}
}
if (response.status < 400) {
return responseData;
} else {
throw new Error(responseData.message);
}
} catch (error) {
if (error.name != ABORT_ERROR_NAME) {
throw error;
}
}
function fetchContentData(method, body) {
return fetch(`${GITHUB_API_URL}/${REPOS_PATH}/${userName}/${repositoryName}/${CONTENTS_PATH}/${path}`, {
method,
headers,
body,
signal
});
}
}
function splitFilename(filename) {View on GitHub (pinned to 517fb7c5cf)
Solutions
- Log the error message to see GitHub's exact reason; branch on it (credentials vs not-found vs conflict vs rate limit).
- For "already exists" conflicts, fetch the current file's SHA and pass it to update the content instead of creating.
- For 401, regenerate the PAT/refresh the token and ensure required scopes (repo / Contents: write for fine-grained tokens).
- For 403 rate limit, add backoff and reduce request volume; check X-RateLimit-Remaining headers.
- Verify repo name, branch, and path spelling and that the branch exists.
Example fix
// before
await github.createContent({...}); // Error: sha wasn't supplied
// after
try {
await github.createContent({..., content, message});
} catch (e) {
if (/already exists|sha wasn't supplied/i.test(e.message)) {
const existing = await github.getFileSha(path);
await github.createContent({..., sha: existing.sha});
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight checks before createContent
if (!token || token.length < 20) throw new Error("GitHub token missing/short");
if (!/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error("repo must be owner/name");
// check whether the file already exists to fetch its SHA for updates Try / catch
try { await github.createContent(params); }
catch (e) {
const msg = String(e.message);
if (/Bad credentials/i.test(msg)) return reauthGitHub();
if (/Not Found/i.test(msg)) return verifyRepoAndBranch();
if (/already exists|sha/i.test(msg)) return updateWithSha(params);
if (/rate limit/i.test(msg)) return retryWithBackoff();
throw e;
} Prevention
- Fetch the existing file's SHA before writing over an existing path
- Check X-RateLimit-Remaining and back off before hitting limits
- Use fine-grained PATs with Contents: write for private repos
- Rotate/validate tokens in CI before runs
When it happens
Trigger: Uploading/creating a file where status >= 400: 401 bad or expired personal access token; 404 repo or branch/path does not exist; 422 commit conflict because the file changed and no SHA was supplied for update; 403 rate limit or resource not accessible.
Common situations: Token expired or rotated causing "Bad credentials"; writing to a repo path where the file already exists without passing its blob SHA (must use update); private repo with a fine-grained token lacking Contents write permission; hitting the 5000 req/hr REST limit in CI loops.
Related errors
- error.message + " (RestFormApi)"
- unknown_error
- MCP server error: ${response.status} ${response.statusText}
- await response.text()
AI-assisted analysis of gildas-lormeau/SingleFile@517fb7c5cf (2026-09-01).
Data as JSON: /api/errors/8d0c1b812ead9c2d.
Report an issue: GitHub.