ory/kratos · error
unknown courier channel type
Error message
unknown courier channel type: %s
What it means
The courier dispatcher resolves a configured channel by ID, switching on channel.Type. Only sms, email (implied cases) and "http" are supported; any other type string makes the channels method return this error. It signals an invalid channel type in the courier configuration.
Solutions
- Set the channel type to a supported value: sms, email, or http.
- Fix typos in the courier config's channels[].type field.
- Check the docs/version for the exact set of supported channel types in your release.
- Validate the config before startup to catch the bad type early.
Example fix
// before (config.yaml)
courier:
channels:
- id: sms
type: smss
// after
courier:
channels:
- id: sms
type: http
request_config: {...} Defensive patterns
Strategy: validation
Validate before calling
supported := map[string]bool{"sms": true, "email": true, "http": true}
for _, ch := range cfg.Courier.Channels {
if !supported[ch.Type] {
return fmt.Errorf("channel %q has unsupported type %q", ch.ID, ch.Type)
}
} Type guard
func isSupportedChannelType(t string) bool {
switch t { case "sms", "email", "http": return true }
return false
} Try / catch
if err := courier.DispatchMessage(ctx, msg); err != nil {
if strings.Contains(err.Error(), "unknown courier channel type") {
log.Printf("config error: %v", err) // fix courier.channels types
return nil // or dead-letter the message
}
return err
} Prevention
- Validate courier config against the JSON schema at startup
- Only use channel types documented for your release
- Lint config files in CI to catch typos like smss/htpp
When it happens
Trigger: Courier config contains a channel whose type is not one of the recognized values (e.g. type: webhook or a typo like htpp/smss), and a message is dispatched to that channel ID.
Common situations: Typos in the YAML/JSON config channel type, copying config snippets from newer/older versions where a channel type was added or removed, or inventing a custom type expecting generic HTTP behavior.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- no courier channels configured for
- expected to get the DSN as an argument, or the…
- required config value "dsn" was not set
- you must provide `secrets.pagination` for FIPS compliance
- you must provide `secrets.cipher` for FIPS compliance
AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07).
Data as JSON: /api/errors/668ecfda2bacb4d7.
Report an issue: GitHub.
Appendix: source
Thrown at courier/courier_dispatcher.go:39
if err != nil {
return nil, err
}
for _, channel := range cs {
if channel.ID != id {
continue
}
switch channel.Type {
case "smtp":
courierChannel, err := NewSMTPChannelWithCustomTemplates(c.deps, channel.SMTPConfig, c.newEmailTemplateFromMessage)
if err != nil {
return nil, err
}
return courierChannel, nil
case "http":
return newHttpChannel(channel.ID, &channel.RequestConfig, c.deps), nil
default:
return nil, errors.Errorf("unknown courier channel type: %s", channel.Type)
}
}
return nil, errors.Errorf("no courier channels configured for: %s", id)
}
func (c *courier) DispatchMessage(ctx context.Context, msg Message) (err error) {
ctx, span := c.deps.Tracer(ctx).Tracer().Start(ctx, "courier.DispatchMessage", trace.WithAttributes(
attribute.Stringer("message.id", msg.ID),
attribute.Stringer("message.nid", msg.NID),
attribute.Stringer("message.type", msg.Type),
attribute.String("message.template_type", string(msg.TemplateType)),
attribute.Int("message.send_count", msg.SendCount),
))
defer otelx.End(span, &err)
ctx = semconv.ContextWithAttributes(ctx, semconv.AttrNID(msg.NID))
logger := c.deps.Logger().View on GitHub (pinned to b86338da04)