ory/kratos · error
failed to unmarshal notify_previous_addresses configuration…
Error message
failed to unmarshal notify_previous_addresses configuration for %s: %w
What it means
getHooks decodes a notify_previous_addresses hook's optional JSON config into hook.NotifyPreviousAddressesConfig. If the raw bytes are non-empty but invalid JSON or of the wrong shape, construction of the hook chain is aborted with this wrapped error naming the credentials type. Unlike the web_hook case, an empty config is tolerated.
Solutions
- Fix the JSON so it parses and matches hook.NotifyPreviousAddressesConfig field types
- Leave the config field empty/null if no options are needed — empty config is allowed
- Validate with jq -e against the expected schema before applying config
- Inspect raw_config in the error log to identify the exact malformed input
Example fix
// before
{"job": "notify_previous_addresses", "config": ["a", "b"]}
// after
{"job": "notify_previous_addresses", "config": {}} Defensive patterns
Strategy: validation
Validate before calling
// Go: validate notify_previous_addresses config before use
func validNotifyPrevConfig(raw json.RawMessage) error {
if len(raw) == 0 {
return nil // empty config is allowed
}
var cfg hook.NotifyPreviousAddressesConfig
return json.Unmarshal(raw, &cfg)
} Type guard
func isNotifyPrevConfigOK(raw json.RawMessage) bool {
if len(raw) == 0 {
return true
}
var cfg hook.NotifyPreviousAddressesConfig
return json.Unmarshal(raw, &cfg) == nil
} Try / catch
hooks, err := reg.PostRecoveryHooks(ctx, credentialsType)
if err != nil {
log.WithError(err).Error("check notify_previous_addresses hook config JSON")
return err
} Prevention
- Omit the config field entirely when the hook needs no options — empty is valid
- Lint YAML→JSON conversion to ensure it produces an object, not an array
- Validate config with a schema checker in CI before deploy
- Copy hook config only from known-good fixtures
When it happens
Trigger: A hook with key "notify_previous_addresses" has a non-empty Config field that fails json.Unmarshal into &hook.NotifyPreviousAddressesConfig{} (malformed JSON or incompatible field types).
Common situations: Hand-edited JSON in Kratos config with typos; pasting YAML into the JSON config block; wrapping the config in an extra array; using the wrong casing for config keys after copy-paste between environments.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- failed to unmarshal webhook configuration for
- unexpected node type
- boolean unmarshal error: invalid input
- no credentials found
- api_key auth strategy requires a string name
AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07).
Data as JSON: /api/errors/acf578f6d930b812.
Report an issue: GitHub.
Appendix: source
Thrown at driver/registry_default_hooks.go:114
}
case hook.KeyVerificationUI:
if h, ok := any(m.HookShowVerificationUI()).(T); ok {
hooks = append(hooks, h)
}
case hook.KeyVerifier:
if h, ok := any(m.HookVerifier()).(T); ok {
hooks = append(hooks, h)
}
case hook.KeyVerifyNewAddress:
if h, ok := any(m.HookVerifyNewAddress()).(T); ok {
hooks = append(hooks, h)
}
case hook.KeyNotifyPreviousAddresses:
cfg := &hook.NotifyPreviousAddressesConfig{}
if len(hookConfig.Config) > 0 {
if err := json.Unmarshal(hookConfig.Config, cfg); err != nil {
m.l.WithError(err).WithField("raw_config", string(hookConfig.Config)).Error("failed to unmarshal hook configuration, ignoring hook")
return nil, errors.WithStack(fmt.Errorf("failed to unmarshal notify_previous_addresses configuration for %s: %w", credentialsType, err))
}
}
if h, ok := any(m.HookNotifyPreviousAddresses(cfg)).(T); ok {
hooks = append(hooks, h)
}
default:
for name, newHook := range m.injectedSelfserviceHooks {
if name == hookConfig.Name {
if h, ok := newHook(hookConfig, m).(T); ok {
hooks = append(hooks, h)
}
continue allHooksLoop
}
}
m.l.
WithField("for", credentialsType).
WithField("hook", hookConfig.Name).
Warn("A configuration for a non-existing hook was found and will be ignored.")View on GitHub (pinned to b86338da04)