GopeedLab/gopeed · error

invalid resource name

Error message

invalid resource name

What it means

base.Resource.Validate() (pkg/base/model.go:96) requires a non-empty Name on the resolved resource. A Resource describes what a fetcher resolved (name, size, range support, file list); the name doubles as the target file/folder name, so an empty one cannot be used to write output.

Source

Thrown at pkg/base/model.go:98

	return http.ProxyURL(util.BuildProxyUrl(p.Scheme, p.Host, p.Usr, p.Pwd))
}

// 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
		}

View on GitHub (pinned to 7b7327ffb3)

Solutions

  1. Populate Name before Validate — typically from Content-Disposition or the URL path base
  2. In custom fetchers, default the name (e.g. url basename or host+timestamp) instead of leaving it empty
  3. When decoding, require the name key so the failure happens at the boundary

Example fix

// before
res := &base.Resource{Size: 1024, Files: files} // Name zero value
err := res.Validate() // "invalid resource name"

// after
res := &base.Resource{Name: "file.zip", Size: 1024, Files: files}
err := res.Validate()
Defensive patterns

Strategy: validation

Validate before calling

func resourceName(u string, cd string) string {
    if _, params, err := mime.ParseMediaType(cd); err == nil {
        if n := params["filename"]; n != "" {
            return n
        }
    }
    if base := path.Base(u); base != "/" && base != "." {
        return base
    }
    return "download"
}

Try / catch

if err := res.Validate(); err != nil {
    if strings.Contains(err.Error(), "invalid resource name") {
        res.Name = fallbackName(req.URL) // derive from URL/headers, then re-validate
        return res.Validate()
    }
    return err
}

Prevention

When it happens

Trigger: Building a Resource programmatically and leaving Name zero; a protocol extension returning a resolved resource without deriving a name from the URL or Content-Disposition; deserializing JSON that lacked the name field.

Common situations: Custom fetcher implementations that forget to populate Name; servers responding without a usable filename; refactors that rename the field and silently break deserialization.

Related errors


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