{"record":{"id":"7b3442345ee0aa88","repo":"siyuan-note/siyuan","slug":"parse-template-s-failed-s","errorCode":null,"errorMessage":"parse template [%s] failed: %s","messagePattern":"parse template \\[(.+?)\\] failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/av/calc_template.go","lineNumber":92,"sourceCode":"\t\tctx[\"min\"] = float64(0)\n\t\tctx[\"max\"] = float64(0)\n\t\tctx[\"median\"] = float64(0)\n\t}\n\treturn ctx\n}\n\n// evalRollupTemplate 使用 text/template + sprig 渲染自定义模板统计内容。\n// 返回渲染后的字符串；若该字符串可解析为数字则 isNumber 为 true 且 asNumber 为该数值。\n// 解析或执行失败时返回 err，由调用方决定如何提示用户。\nfunc evalRollupTemplate(templateContent string, ctx map[string]any) (rendered string, asNumber float64, isNumber bool, err error) {\n\tif \"\" == templateContent {\n\t\treturn\n\t}\n\n\tgoTpl := template.New(\"\").Delims(\".action{\", \"}\").Funcs(templateFuncMap())\n\ttpl, parseErr := goTpl.Parse(templateContent)\n\tif nil != parseErr {\n\t\terr = fmt.Errorf(\"parse template [%s] failed: %s\", templateContent, parseErr)\n\t\treturn\n\t}\n\n\tbuf := &bytes.Buffer{}\n\tif execErr := tpl.Execute(buf, ctx); nil != execErr {\n\t\terr = fmt.Errorf(\"execute template [%s] failed: %s\", templateContent, execErr)\n\t\treturn\n\t}\n\n\trendered = buf.String()\n\tif \"<no value>\" == rendered {\n\t\trendered = \"\"\n\t\treturn\n\t}\n\n\t// 渲染结果若可解析为数字，则按数字处理（前端会按列数字格式显示）\n\ttrimmed := strings.TrimSpace(rendered)\n\tif \"\" != trimmed {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/av/calc_template.go#L74-L110","documentation":"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.","triggerScenarios":"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{ }.","commonSituations":"Writing '.action{{ .sum }}' instead of '.action{ .sum }'; unbalanced parentheses; calling an undefined sprig function; copying a Helm/Go template verbatim that uses different delimiters.","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)."],"exampleFix":"// before\nconfig.Template = \"{{ .sum }} / {{ .count }}\"\n// after\nconfig.Template = \".action{ .sum } / .action{ .count }\"","handlingStrategy":"validation","validationCode":"// Pre-validate a user-entered template before saving it on the calc.\nfunc validateCalcTemplate(tpl string) error {\n    if tpl == \"\" {\n        return nil\n    }\n    goTpl := template.New(\"\").Delims(\".action{\", \"}\").Funcs(template.FuncMap{\n        // surface the same funcs the kernel uses, or stub them\n    })\n    if _, err := goTpl.Parse(tpl); err != nil {\n        return err\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// The kernel already toasts parse errors via pushRollupTemplateErr.\n// In your own calc driver, mirror that handling:\nif _, _, _, err := evalRollupTemplate(tpl, ctx); err != nil {\n    logging.LogErrorf(\"rollup template failed: %s\", err)\n    util.PushErrMsg(err.Error(), 30000)\n    return // leave calc.Result empty\n}","preventionTips":["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 {{ }}."],"tags":["template","av","rollup","calc","text-template","sprig"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}