twpayne/chezmoi · error
%s: no URL
Error message
%s: no URL
What it means
Returned by SourceState.readExternalData when an external entry declares no usable URL: every url in the external's url list failed to parse, so firstURLStr was never set. chezmoi requires at least one valid URL to fetch external assets from.
Source
Thrown at internal/chezmoi/sourcestate.go:1804
options *ReadOptions,
) ([]byte, string, error) {
var firstURLStr string
var firstErr error
for _, urlStr := range append([]string{external.URL}, external.URLs...) {
if urlStr == "" {
continue
}
data, err := s.getExternalDataRaw(ctx, externalRelPath, urlStr, external.RefreshPeriod, options)
if err == nil {
return data, urlStr, nil
}
if firstURLStr == "" {
firstURLStr = urlStr
firstErr = err
}
}
if firstURLStr == "" {
return nil, "", fmt.Errorf("%s: no URL", externalRelPath)
}
return nil, firstURLStr, firstErr
}
// getExternalDataRaw returns the raw data for external at externalRelPath,
// possibly from the external cache.
func (s *SourceState) getExternalDataRaw(
ctx context.Context,
externalRelPath RelPath,
urlStr string,
refreshPeriod Duration,
options *ReadOptions,
) ([]byte, error) {
// Handle file:// URLs by always reading from disk.
switch urlStruct, err := url.Parse(urlStr); {
case err != nil:
return nil, err
case urlStruct.Scheme == "file":View on GitHub (pinned to f901167e46)
Solutions
- Fix the url value in the .chezmoiexternal entry to be a valid absolute URL (percent-encode spaces, no stray whitespace)
- Run chezmoi with --verbose or validate the URL with a quick url.Parse in Go to confirm it parses
- Quote or template-escape the URL if it is generated from template values
Example fix
// before
[.vim]
url = ["https://example.com/my dotfiles.zip"]
// after
[.vim]
url = ["https://example.com/my%20dotfiles.zip"] Defensive patterns
Strategy: validation
Validate before calling
// validate external URLs before applying
for _, u := range extCfg.URLs {
if _, err := url.Parse(strings.TrimSpace(u)); err != nil {
return fmt.Errorf("external %q has invalid url %q: %w", extCfg.RelPath, u, err)
}
} Prevention
- Keep URLs ASCII and percent-encoded
- Trim template-generated URL strings
- Run chezmoi apply --dry-run in CI to catch config errors early
When it happens
Trigger: Running chezmoi apply/init with an .chezmoiexternal entry whose url list contains only URLs that fail url.Parse (e.g. containing spaces or invalid characters), so no firstURLStr is ever recorded before the check.
Common situations: Hand-edited .chezmoiexternal.toml/yaml with a malformed URL (unescaped spaces, stray characters); templating that produced an empty or broken URL; copy-pasted URLs with whitespace.
Related errors
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/ad3a463243044fd6.
Report an issue: GitHub.