AlistGo/alist · error

failed to render download_params: %w

Error message

failed to render download_params: %w

What it means

While building a download link, the url_tree driver executes the previously parsed download_params template with the node's magic variables (Name, Path, Size, Modified). Execution fails if the template references a field that is not provided or a function errors at runtime; the error is wrapped and the Link call fails for that file.

Source

Thrown at drivers/url_tree/driver.go:118

		return &model.Link{
			URL: downURL,
		}, nil
	}
	return nil, errs.NotFile
}

// buildDownloadURL renders the configured download_params template with the
// node's magic variables and appends the result as query parameters to the URL.
func (d *Urls) buildDownloadURL(node *Node, path string) (string, error) {
	var sb strings.Builder
	err := d.downloadParamsTmpl.Execute(&sb, map[string]interface{}{
		"Name":     node.Name,
		"Path":     path,
		"Size":     node.Size,
		"Modified": node.Modified,
	})
	if err != nil {
		return "", fmt.Errorf("failed to render download_params: %w", err)
	}
	rendered := strings.TrimSpace(sb.String())
	rendered = strings.TrimPrefix(rendered, "?")
	if rendered == "" {
		return node.Url, nil
	}
	// Parse the rendered string so that magic-variable values (e.g. file names
	// with non-ASCII characters) are properly URL-encoded by Encode().
	query, err := url.ParseQuery(rendered)
	if err != nil {
		return "", fmt.Errorf("invalid download_params %q: %w", rendered, err)
	}
	return utils.InjectQuery(node.Url, query)
}

func (d *Urls) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
	if !d.Writable {
		return nil, errs.PermissionDenied

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Restrict template fields to exactly Name, Path, Size, Modified; fix typos such as {{.Filename}} -> {{.Name}}.
  2. Test the template with dummy values mirroring those four keys to confirm it renders.
  3. Simplify: remove custom template functions; text/template built-ins only are supported.

Example fix

// before
download_params = "fname={{.Filename}}"

// after
download_params = "fname={{.Name}}"
Defensive patterns

Strategy: validation

Validate before calling

var allowedFields = map[string]bool{"Name": true, "Path": true, "Size": true, "Modified": true}
// after parsing, walk template.Tree and reject .Field lookups not in allowedFields
func checkFields(t *template.Template) error {
    _, err := t.Execute(nil, map[string]any{"Name": "x", "Path": "/x", "Size": int64(1), "Modified": int64(0)})
    return err // nil map input still executes field lookups; use dummy values
}

Try / catch

url, err := d.buildDownloadURL(node, path)
if err != nil && strings.Contains(err.Error(), "failed to render") {
    // log node identity and template; fall back to raw node.Url if acceptable
}

Prevention

When it happens

Trigger: A template that parsed fine but references {{.Missing}} (nil field) or uses functions that error during Execute when called from buildDownloadURL for a specific node/path.

Common situations: Typo in a field name like {{.Filename}} instead of {{.Name}}, or expecting per-node fields that the driver does not inject. Storage initializes fine but every download fails.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/c045431f2eee5943. Report an issue: GitHub.