AlistGo/alist · error
res.Status
Error message
res.Status
What it means
This is the blob-upload failure path in putBlob: the GitHub Contents API was expected to return HTTP 201 (Created) but returned another status, and the response body could not be unmarshalled into the ErrResp struct, so the driver falls back to surfacing the bare HTTP status line (e.g. '401 Unauthorized', '404 Not Found', '403 rate limit exceeded').
Source
Thrown at drivers/github/driver.go:735
token := strings.TrimSpace(d.Token)
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
req.ContentLength = length
res, err := base.HttpClient.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
resBody, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
if res.StatusCode != 201 {
var errMsg ErrResp
if err = utils.Json.Unmarshal(resBody, &errMsg); err != nil {
return "", errors.New(res.Status)
} else {
return "", fmt.Errorf("%s: %s", res.Status, errMsg.Message)
}
}
var resp PutBlobResp
if err = utils.Json.Unmarshal(resBody, &resp); err != nil {
return "", err
}
return resp.Sha, nil
}
func (d *Github) renewParentTrees(path, prevSha, curSha, until string) (string, error) {
for path != until {
path = stdpath.Dir(path)
tree, sha, err := d.getTreeDirectly(path)
if err != nil {
return "", err
}View on GitHub (pinned to 843d9dc814)
Solutions
- Verify the token: it must have write access to the target repo (classic token: 'repo' scope; fine-grained: Contents read/write)
- Check owner/repo spelling and that the repo exists and is accessible to the token
- Check rate-limit headers (X-RateLimit-Remaining) and retry after Retry-After; reduce upload concurrency
- If GitHub returns 5xx, wait and retry later
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight token and repo accessibility
req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/repos/%s/%s", owner, repo), nil)
req.Header.Set("Authorization", "Bearer "+token)
res, _ := http.DefaultClient.Do(req)
if res.StatusCode != 200 { return fmt.Errorf("preflight failed: %s", res.Status) } Try / catch
sha, err := d.putBlob(ctx, stream, up)
if err != nil {
if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "403") {
return fmt.Errorf("token lacks write access or rate-limited: %w", err)
}
if strings.HasSuffix(err.Error(), "Server Error") || strings.Contains(err.Error(), "5") {
time.Sleep(backoff); return d.putBlob(ctx, stream, up) // transient
}
return err
} Prevention
- Use a classic PAT with 'repo' scope or fine-grained PAT with Contents: read+write on the target repo
- Watch X-RateLimit-Remaining on responses and back off near zero
- Keep upload concurrency low to avoid secondary rate limits
- Alert on 401s so expired tokens are rotated quickly
When it happens
Trigger: POST to repos/{owner}/{repo}/git/blobs returns non-201: 401 when the token is invalid/expired, 403 for missing repo scope or rate limiting, 404 for wrong repo/owner or private repo without auth, 5xx on GitHub outages — and the body is empty/HTML instead of the expected JSON error envelope.
Common situations: Personal access token lacking 'Contents: read and write' permission (fine-grained PATs), token expired, repo renamed or deleted, secondary rate limits during bulk uploads, GitHub API incident.
Related errors
- res.Status()
- resp.String()
- getSessionToken :: failed to get session token, status code:
- rename failed with status %d
- streamtape upload failed: http %d
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/ab2f03eb673948b2.
Report an issue: GitHub.