twpayne/chezmoi · error

%s: missing path

Error message

%s: missing path

What it means

Returned by readExternalArchive when the external entry's archivePath field is empty, i.e. an entry that requires selecting a file within an archive has no path specified. chezmoi cannot know which member of the archive to extract.

Source

Thrown at internal/chezmoi/sourcestate.go:2645

	format := external.Format
	if format == ArchiveFormatUnknown {
		format = GuessArchiveFormat(urlPath, data)
	}

	return data, urlStr, format, nil
}

// readExternalArchiveFile reads a file from an external archive and returns its
// SourceStateEntries.
func (s *SourceState) readExternalArchiveFile(
	ctx context.Context,
	externalRelPath RelPath,
	parentSourceRelPath SourceRelPath,
	external *External,
	options *ReadOptions,
) (map[RelPath][]SourceStateEntry, error) {
	if external.ArchivePath.IsEmpty() {
		return nil, fmt.Errorf("%s: missing path", externalRelPath)
	}

	data, urlStr, format, err := s.readExternalArchiveData(ctx, externalRelPath, external, options)
	if err != nil {
		return nil, err
	}

	var sourceStateEntry SourceStateEntry
	if err := WalkArchive(data, format, func(name RelPath, fileInfo fs.FileInfo, r io.Reader, linkname string) error {
		if external.StripComponents > 0 {
			components := name.SplitAll()
			if len(components) <= external.StripComponents {
				return nil
			}
			name = NewRelPathFromComponents(components[external.StripComponents:]...)
		}
		switch {
		case name.IsEmpty():

View on GitHub (pinned to f901167e46)

Solutions

  1. Add the path field naming the file inside the archive to extract
  2. If the whole archive is wanted, change type to plain archive and remove the path expectation
  3. Validate with chezmoi apply --dry-run after editing

Example fix

// before
[.local/bin/jq]
    type = "archive-file"
    url = "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64"
// after
[.local/bin/jq]
    type = "archive-file"
    url = "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64"
    path = "jq"
Defensive patterns

Strategy: validation

Validate before calling

if ext.Type == "archive-file" && ext.Path == "" {
    return fmt.Errorf("archive-file external %q requires a path", name)
}

Type guard

func archiveFileHasPath(e External) bool { return e.Type != "archive-file" || e.Path != "" }

Prevention

When it happens

Trigger: An external entry of type archive-file (or one using archive.path/executable selection) is configured without the path key, so external.ArchivePath.IsEmpty() is true.

Common situations: Using the executable/archive-file external style but forgetting the path; renaming config keys and dropping path; copying an archive-type entry and converting it incompletely.

Related errors


AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01). Data as JSON: /api/errors/b13ba903538eb3a0. Report an issue: GitHub.