twpayne/chezmoi · error
%s: %s: %s
Error message
%s: %s: %s
What it means
Returned by SourceState.getExternalDataRaw when the HTTP response status is outside 200-299 (and not a multiple-choice redirect). It wraps the URL and the server's status text so the developer sees which remote request failed and why.
Source
Thrown at internal/chezmoi/sourcestate.go:1884
if err != nil {
return nil, err
}
resp, err := chezmoilog.LogHTTPRequest(ctx, s.logger, s.httpClient, req)
if err != nil {
return nil, err
}
var data []byte
if options == nil || options.ReadHTTPResponse == nil {
data, err = io.ReadAll(resp.Body)
} else {
data, err = options.ReadHTTPResponse(urlStr, resp)
}
_ = resp.Body.Close()
if err != nil {
return nil, err
}
if resp.StatusCode < http.StatusOK || http.StatusMultipleChoices <= resp.StatusCode {
return nil, fmt.Errorf("%s: %s: %s", externalRelPath, urlStr, resp.Status)
}
if err := MkdirAll(s.baseSystem, cachedDataAbsPath.Dir(), 0o700); err != nil {
return nil, err
}
if err := s.baseSystem.WriteFile(cachedDataAbsPath, data, 0o600); err != nil {
return nil, err
}
if err := s.baseSystem.Chtimes(cachedDataAbsPath, now, now); err != nil {
return nil, err
}
return data, nil
}
// newCreateTargetStateEntryFunc returns a targetStateEntryFunc that returns a
// file with the value of sourceContentsFunc if the file does not already exist,
// or returns the actual file's contents unchanged if the file already exists.View on GitHub (pinned to f901167e46)
Solutions
- Open the url from the error in a browser/curl and fix it in .chezmoiexternal (e.g. update to the new release tag)
- If authentication is required, configure credentials or use a token-authenticated URL
- Add a fallback second url entry so chezmoi can retry with a mirror
Example fix
// before url = "https://github.com/user/repo/archive/v1.2.3.tar.gz" // after url = "https://github.com/user/repo/archive/v1.2.4.tar.gz"
Defensive patterns
Strategy: retry
Validate before calling
// check URL reachability before pinning it
resp, err := http.Head(url); if err != nil || resp.StatusCode != 200 { /* pick another url */ } Try / catch
// wrap apply and retry once on non-2xx
if err := chezmoiApply(); err != nil {
if strings.Contains(err.Error(), ": 4") || strings.Contains(err.Error(), ": 5") {
refreshExternalURL(); retry()
}
} Prevention
- Pin external URLs to stable release tags, not moving targets
- Provide a fallback mirror URL in the external entry
- Monitor upstream repos for renamed/moved release assets
When it happens
Trigger: chezmoi downloads an external asset (archive/file) and the server replies 404, 403, 500, etc.; resp.StatusCode < 200 || >= 300 triggers this before caching the data.
Common situations: External URL points at a moved/renamed GitHub release asset (404); private repo asset fetched without auth (403); rate-limited or misconfigured mirror (5xx); tag changed upstream.
Related errors
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/e900e4ed7af4d92b.
Report an issue: GitHub.