siyuan-note/siyuan · warning
parse template [%s] failed: %s
Error message
parse template [%s] failed: %s
What it means
Thrown by evalRollupTemplate when Go's text/template cannot parse the user-supplied calc/rollup 'Template' operator string. SiYuan uses custom delimiters '.action{' and '}' (not the usual {{ }}) on top of sprig plus a custom countif function. A parse error means the template grammar itself is malformed, independent of any data.
Source
Thrown at kernel/av/calc_template.go:92
ctx["min"] = float64(0)
ctx["max"] = float64(0)
ctx["median"] = float64(0)
}
return ctx
}
// evalRollupTemplate 使用 text/template + sprig 渲染自定义模板统计内容。
// 返回渲染后的字符串;若该字符串可解析为数字则 isNumber 为 true 且 asNumber 为该数值。
// 解析或执行失败时返回 err,由调用方决定如何提示用户。
func evalRollupTemplate(templateContent string, ctx map[string]any) (rendered string, asNumber float64, isNumber bool, err error) {
if "" == templateContent {
return
}
goTpl := template.New("").Delims(".action{", "}").Funcs(templateFuncMap())
tpl, parseErr := goTpl.Parse(templateContent)
if nil != parseErr {
err = fmt.Errorf("parse template [%s] failed: %s", templateContent, parseErr)
return
}
buf := &bytes.Buffer{}
if execErr := tpl.Execute(buf, ctx); nil != execErr {
err = fmt.Errorf("execute template [%s] failed: %s", templateContent, execErr)
return
}
rendered = buf.String()
if "<no value>" == rendered {
rendered = ""
return
}
// 渲染结果若可解析为数字,则按数字处理(前端会按列数字格式显示)
trimmed := strings.TrimSpace(rendered)
if "" != trimmed {View on GitHub (pinned to 251596fc0d)
Solutions
- Replace {{ / }} delimiters with .action{ / } (the kernel's custom delimiters at calc_template.go:89).
- Strip the template down to a literal plus one field reference (e.g. .action{ .sum }) and re-add complexity until it breaks to isolate the syntax error.
- Cross-check function names against sprig's documentation and the custom countif; note env/expandenv/getHostByName are deliberately removed for security (calc_template.go:187-189).
Example fix
// before
config.Template = "{{ .sum }} / {{ .count }}"
// after
config.Template = ".action{ .sum } / .action{ .count }" Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate a user-entered template before saving it on the calc.
func validateCalcTemplate(tpl string) error {
if tpl == "" {
return nil
}
goTpl := template.New("").Delims(".action{", "}").Funcs(template.FuncMap{
// surface the same funcs the kernel uses, or stub them
})
if _, err := goTpl.Parse(tpl); err != nil {
return err
}
return nil
} Try / catch
// The kernel already toasts parse errors via pushRollupTemplateErr.
// In your own calc driver, mirror that handling:
if _, _, _, err := evalRollupTemplate(tpl, ctx); err != nil {
logging.LogErrorf("rollup template failed: %s", err)
util.PushErrMsg(err.Error(), 30000)
return // leave calc.Result empty
} Prevention
- Run the user's template through text/template with delimiters '.action{' '}' before persisting it.
- Provide a live preview in the UI that renders the template against sample data.
- Document the custom delimiters prominently — most users default to {{ }}.
When it happens
Trigger: User selects the 'Template' calculation operator on an Attribute View column and enters a string with unclosed actions, bad pipelines, or a typo'd function name. Also fires when someone uses standard {{ }} delimiters out of habit, since SiYuan's parser only recognizes .action{ }.
Common situations: Writing '.action{{ .sum }}' instead of '.action{ .sum }'; unbalanced parentheses; calling an undefined sprig function; copying a Helm/Go template verbatim that uses different delimiters.
Related errors
- execute template [%s] failed: %s
- encrypted notebook is locked, please unlock it first
- new item templates config is nil
- clone new item template failed
- new item template name is empty
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/7b3442345ee0aa88.
Report an issue: GitHub.