docker/cli · error
failed to parse hook template
Error message
failed to parse hook template
What it means
ErrHookTemplateParse is a sentinel error (errors.New at cli-plugins/hooks/template.go:49) that is wrapped (via %w) by commandInfo.flagValue and commandInfo.argValue when a plugin's hook-message template references data that cannot be resolved. It fires when the template calls {{flagValue "x"}} for a flag that does not exist on the command, {{argValue n}} for an argument index that was not passed, or when the cobra command context (cmd) is nil. The text/template parse/execute step itself can also surface a wrapped error here.
Solutions
- Inspect the plugin's hook Response.Template string and cross-check every {{flagValue "name"}} / {{argValue n}} against the actual flags and positional args of the command that triggers the hook.
- Use the documented backward-compatible funcs {{command}} and {{flagValue}} (not the deprecated {{flag}}/{{arg}}) and confirm the flag name matches exactly.
- If authoring the hook in a test, ensure a non-nil *cobra.Command with the expected flags registered is passed to hooks.ParseTemplate.
- Run the CLI with DOCKER_CLI_HOOKS=0 or remove the offending plugin entry from config.json to confirm the template is the culprit.
Example fix
// before (template references a flag that does not exist on 'docker context ls')
Template: `hint: use {{flagValue "format"}} for JSON`
// after — use a flag that actually exists, or drop the directive
Template: `hint: run 'docker context show' to see the active context` Defensive patterns
Strategy: validation
Validate before calling
// Before installing/invoking a hook, dry-run the template against a representative command:
cmd, _ := fakeCobraCmdWithFlags("context", []string{"ls"}) // register the flags the template uses
if _, err := hooks.ParseTemplate(pluginResponse.Template, cmd); err != nil {
log.Printf("hook template invalid: %v", err)
// do not register this hook
} Type guard
// Detect the sentinel via errors.Is (it is wrapped with %w):
func isHookTemplateParseErr(err error) bool { return errors.Is(err, hooks.ErrHookTemplateParse) } Try / catch
// In the plugin host (already done by the manager): wrap per-plugin invocation so a bad template
// degrades to a Debug log instead of failing the CLI:
if _, _, err := tryInvokeHook(name, cfg); err != nil {
if errors.Is(err, hooks.ErrHookTemplateParse) {
logrus.WithError(err).WithField("plugin", name).Debug("hook template parse failed; skipping")
continue
}
return err
} Prevention
- Cross-check every {{flagValue "x"}} against the command's actual registered flags before shipping a hook template.
- Prefer {{command}} and {{argValue n}} only for args you know are present; guard arg indices against NArg().
- Add a unit test that runs hooks.ParseTemplate with a realistic *cobra.Command for each hook you ship.
- Version your templates with the CLI version they target; flag sets change across releases.
When it happens
Trigger: Configuring a plugin hook in ~/.docker/config.json whose "hooks"/"error-hooks" value triggers a plugin that emits a Response.Template containing {{flagValue "someFlag"}} where "someFlag" is not a registered flag on the executed command, or {{argValue 3}} when fewer than 4 positional args were supplied, or invoking a hook path whose cobra command was not populated.
Common situations: Plugin authors copying a hook template from documentation for a different subcommand (flags differ between e.g. 'docker image ls' and 'docker context ls'); templates written against an older CLI version referencing flags that were renamed/removed; running the hook subcommand in a test harness that passes a nil *cobra.Command.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- hook template contains too many messages
- failed to parse hook template: flagValue: no flags found
- failed to parse hook template: arg: %dth argument not set
- unexpected hook response type
- plugin SchemaVersion version cannot be empty
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/daf9ce468b1c3f12.
Report an issue: GitHub.
Appendix: source
Thrown at cli-plugins/hooks/template.go:49
"arg": func(_ any, i int) (string, error) { return msgContext.argValue(i) },
}).Parse(hookTemplate)
if err != nil {
return nil, err
}
var b bytes.Buffer
err = tmpl.Execute(&b, msgContext)
if err != nil {
return nil, err
}
out = b.String()
}
if n := strings.Count(out, "\n"); n > maxMessages {
return nil, fmt.Errorf("hook template contains too many messages (%d): maximum is %d", n, maxMessages)
}
return strings.SplitN(out, "\n", maxMessages), nil
}
var ErrHookTemplateParse = errors.New("failed to parse hook template")
// commandInfo provides info about the command for which the hook was invoked.
// It is used for templated hook-messages.
type commandInfo struct {
cmd *cobra.Command
}
// Name returns the name of the (sub)command for which the hook was invoked.
//
// It's used for backward-compatibility with old templates.
func (c commandInfo) Name() string {
return c.command()
}
// command returns the name of the (sub)command for which the hook was invoked.
func (c commandInfo) command() string {
if c.cmd == nil {
return ""View on GitHub (pinned to 4f84911bfe)