GopeedLab/gopeed · error

invalid resource files

Error message

invalid resource files

What it means

base.Resource.Validate() (pkg/base/model.go:100) requires a non-empty Files slice. The comment on the struct says a resource with a Name is treated as a folder whose entries are the Files list; a resource with no files has nothing to download and is rejected. Each file must in turn carry a non-empty name (a third check after this one).

Source

Thrown at pkg/base/model.go:101

// Resource download resource
type Resource struct {
	// if name is not empty, the resource is a folder and the name is the folder name
	Name string `json:"name"`
	Size int64  `json:"size"`
	// is support range download
	Range bool `json:"range"`
	// file list
	Files []*FileInfo `json:"files"`
	Hash  string      `json:"hash"`
}

func (r *Resource) Validate() error {
	if r.Name == "" {
		return fmt.Errorf("invalid resource name")
	}
	if len(r.Files) == 0 {
		return fmt.Errorf("invalid resource files")
	}
	for _, file := range r.Files {
		if file.Name == "" {
			return fmt.Errorf("invalid resource file name")
		}
	}
	return nil
}

func (r *Resource) CalcSize(selectFiles []int) {
	var size int64
	for i, file := range r.Files {
		if len(selectFiles) == 0 || slices.Contains(selectFiles, i) {
			size += file.Size
		}
	}
	r.Size = size
}

View on GitHub (pinned to 7b7327ffb3)

Solutions

  1. Populate Files with at least one FileInfo before Validate
  2. For folder fetchers, fail loudly when the listing parse yields zero entries instead of validating an empty resource
  3. When decoding external JSON, require a non-empty files array at the boundary

Example fix

// before
res := &base.Resource{Name: "docs"} // no Files
err := res.Validate() // "invalid resource files"

// after
res := &base.Resource{
    Name:  "docs",
    Files: []*base.FileInfo{{Name: "index.html", Size: 2048}},
}
err := res.Validate()
Defensive patterns

Strategy: validation

Validate before calling

func hasFiles(res *base.Resource) bool {
    return res != nil && len(res.Files) > 0
}

// Use before Validate() in folder resolve paths:
// if !hasFiles(res) { return fmt.Errorf("listing produced no files for %s", url) }

Try / catch

if err := res.Validate(); err != nil {
    if strings.Contains(err.Error(), "invalid resource files") {
        // empty listing usually means the parser broke, not an empty folder
        return fmt.Errorf("no files resolved for %q: check the listing parser", res.Name)
    }
    return err
}

Prevention

When it happens

Trigger: Constructing a single-file Resource and leaving Files nil (single files are usually modeled with FileInfo fields elsewhere); a resolve step that parsed a directory listing but matched zero entries; JSON payloads with an empty or missing files array.

Common situations: Custom fetchers for folder downloads whose listing parser broke (selector change, API response shape change) and returned zero entries; hand-built test fixtures; refactors that stopped populating Files.

Related errors


AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16). Data as JSON: /api/errors/ae29cfcc44bb21fb. Report an issue: GitHub.