{"record":{"id":"b80e85ffc2bfe5a3","repo":"vitessio/vitess","slug":"failed-to-execute-template-v","errorCode":null,"errorMessage":"failed to Execute() template: %v","messagePattern":"failed to Execute\\(\\) template: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/throttler/result.go","lineNumber":86,"sourceCode":"\n\tCurrentRate      int64\n\tGoodOrBad        goodOrBadRate\n\tMemorySkipReason string\n\tHighestGood      int64\n\tLowestBad        int64\n\n\tLagRecordNow                 replicationLagRecord\n\tLagRecordBefore              replicationLagRecord\n\tPrimaryRate                  int64\n\tGuessedReplicationRate       int64\n\tGuessedReplicationBacklogOld int\n\tGuessedReplicationBacklogNew int\n}\n\nfunc (r Result) String() string {\n\tvar b strings.Builder\n\tif err := resultStringTemplate.Execute(&b, r); err != nil {\n\t\tpanic(fmt.Sprintf(\"failed to Execute() template: %v\", err))\n\t}\n\treturn b.String()\n}\n\nfunc (r Result) Alias() string {\n\treturn topoproto.TabletAliasString(r.LagRecordNow.Tablet.Alias)\n}\n\nfunc (r Result) TimeSinceLastRateChange() string {\n\tif r.lastRateChange.IsZero() {\n\t\treturn \"n/a\"\n\t}\n\treturn fmt.Sprintf(\"%.1fs\", r.Now.Sub(r.lastRateChange).Seconds())\n}\n\nfunc (r Result) LagBefore() string {\n\tif r.LagRecordBefore.isZero() {\n\t\treturn \"n/a\"","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/throttler/result.go#L68-L104","documentation":"Result.String() renders the throttler result via a statically-defined text/template (resultStringTemplate). Template execution against a struct field set at init time essentially cannot fail at runtime, so any error is treated as an unrecoverable BUG and panics. It means the template and the Result struct are out of sync.","triggerScenarios":"Calling String() on a throttler Result when resultStringTemplate cannot execute — practically only if the template text was modified to reference a field that no longer exists on Result, or template parsing/execution state was corrupted (e.g. custom build, test stub overriding the template).","commonSituations":"Merging code changes that renamed a Result field without updating resultStringTemplate; custom forks or tests that replace the package-level template with a malformed one.","solutions":["Update resultStringTemplate so all referenced fields match the current Result struct definition","Run the throttler unit tests to re-validate template rendering after any Result struct change","If seen in a fork, diff your template against upstream go/vt/throttler/result.go"],"exampleFix":"// before\ntemplate.Must(template.New(\"result\").Parse(\"{{.LagRecordNow.Noo}}\"))\n// after\ntemplate.Must(template.New(\"result\").Parse(\"{{.MaxReplicationLag}}\"))","handlingStrategy":"try-catch","validationCode":"// recover at call boundary in case template state was tampered with\nfunc safeString(r Result) (s string) {\n    defer func() { s = recover().(string) }()\n    return r.String()\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Errorf(\"Result.String panic: %v\", r)\n    }\n}()","preventionTips":["Keep resultStringTemplate and the Result struct in the same file/change","Add a test rendering Result.String() after every struct field change","Never swap the package-level template at runtime"],"tags":["go","panic","template","string-rendering"],"backgroundTag":"template-execution-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}