docker/cli · warning
failed to unmarshal hook response
Error message
failed to unmarshal hook response (%q): %w
What it means
Thrown by the hook manager when json.Unmarshal fails to decode a plugin's hook response (hooks.Response) from the bytes returned by RunHook. The raw response text and the underlying json error are wrapped for diagnostics. A misbehaving plugin that returns non-JSON or a structurally wrong payload triggers it.
Solutions
- Ensure the plugin writes only the JSON Response payload to stdout (send logs to stderr).
- Validate the response against the hooks.Response schema (Type and Template fields).
- Update the plugin to the current hook protocol version.
Defensive patterns
Strategy: try-catch
Validate before calling
if !json.Valid(resp) {
return fmt.Errorf("plugin %s returned non-JSON hook response", pluginName)
} Try / catch
var message hooks.Response
if err := json.Unmarshal(resp, &message); err != nil {
logrus.WithError(err).WithField("plugin", pluginName).Debug("skipping misbehaving plugin")
continue // the manager already skips plugins on error
} Prevention
- Plugins must emit only the JSON Response to stdout; send logs to stderr.
- Keep plugins on the current hook protocol version.
- Use json.Valid as a fast pre-check before unmarshal.
When it happens
Trigger: A plugin hook executable that prints non-JSON to stdout, or emits JSON that does not match the hooks.Response schema (missing/extra fields, wrong types).
Common situations: Plugin writing debug/logs to stdout instead of stderr, returning a partial JSON object, or an older plugin using an incompatible response format.
Related errors
- unexpected hook response type
- failed to parse hook template
- 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
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/e8067426e3f04362.
Report an issue: GitHub.
Appendix: source
Thrown at cli-plugins/manager/hooks.go:91
}
p, err := getPlugin(pluginName, pluginDirs, rootCmd)
if err != nil {
return nil, false, err
}
resp, err := p.RunHook(ctx, hooks.Request{
RootCmd: match,
Flags: flags,
CommandError: cmdErrorMessage,
})
if err != nil {
return nil, false, err
}
var message hooks.Response
if err := json.Unmarshal(resp, &message); err != nil {
return nil, false, fmt.Errorf("failed to unmarshal hook response (%q): %w", string(resp), err)
}
// currently the only hook type
if message.Type != hooks.NextSteps {
return nil, false, errors.New("unexpected hook response type: " + strconv.Itoa(int(message.Type)))
}
messages, err = hooks.ParseTemplate(message.Template, subCmd)
if err != nil {
return nil, false, err
}
return messages, true, nil
}
for pluginName, pluginCfg := range pluginsCfg {
messages, ok, err := tryInvokeHook(pluginName, pluginCfg)
if err != nil {View on GitHub (pinned to 4f84911bfe)