ory/kratos · error
unknown node type: %T
Error message
unknown node type: %T
What it means
During node JSON serialization (MarshalJSON in ui/node/node.go), the library inspects the concrete type of n.Attributes to derive the node type discriminator. If Attributes holds a struct that is not one of the known attribute types, serialization cannot proceed because the emitted "type" field would be meaningless.
Solutions
- Use only the attribute structs the library defines (InputAttributes, TextAttributes, ImageAttributes, ScriptAttributes, AnchorAttributes, DivisionAttributes, ...).
- Check the %T value in the message to identify the unexpected attributes type you set.
- Remove custom attribute structs or add them to the MarshalJSON switch in a fork/patch.
- Ensure refactors did not accidentally assign an internal wrapper struct to Attributes.
Example fix
// before
node.Attributes = &MyCustomAttributes{Foo: "bar"}
// after
node.Attributes = &TextAttributes{NodeType: Text, Text: ctx(TextContext{ID: "my-id"})} Defensive patterns
Strategy: type-guard
Validate before calling
switch n.Attributes.(type) {
case *ui.InputAttributes, *ui.TextAttributes, *ui.ImageAttributes, *ui.ScriptAttributes, *ui.AnchorAttributes, *ui.DivisionAttributes:
// safe to marshal
default:
// unsupported attributes type
} Type guard
func hasMarshalableAttributes(n *ui.Node) bool {
switch n.Attributes.(type) {
case *ui.InputAttributes, *ui.TextAttributes, *ui.ImageAttributes,
*ui.ScriptAttributes, *ui.AnchorAttributes, *ui.DivisionAttributes:
return true
default:
return false
}
} Try / catch
data, err := json.Marshal(node)
if err != nil {
var stackErr interface{ StackTrace() errors.StackTrace }
if errors.As(err, &stackErr) || strings.Contains(err.Error(), "unknown node type") {
log.Error("node has unsupported Attributes type", "err", err)
}
} Prevention
- Only assign the SDK's exported attribute structs to Node.Attributes.
- Never store custom/internal structs in Attributes; convert to a supported type first.
- After refactors, run a round-trip (marshal→unmarshal) test over all node kinds.
When it happens
Trigger: Constructing a Node with an Attributes value of an unsupported/custom *XxxAttributes type (not TextAttributes, InputAttributes, ScriptAttributes, DivisionAttributes, etc.) and then marshaling the node or a flow containing it to JSON.
Common situations: Extending the UI node system with custom attribute structs without forking the library; a refactor renamed/moved an attributes type so it no longer matches the switch; test code populating Attributes with a wrong struct.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- node type and node attributes mismatch: %T !=
- unexpected node type
- : Could not marshal the traits schema. This usually means…
- failed to unmarshal webhook configuration for
- failed to unmarshal notify_previous_addresses configuration…
AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07).
Data as JSON: /api/errors/7a5169e095c2e6e2.
Report an issue: GitHub.
Appendix: source
Thrown at ui/node/node.go:562
t = Text
attr.NodeType = Text
case *InputAttributes:
t = Input
attr.NodeType = Input
case *AnchorAttributes:
t = Anchor
attr.NodeType = Anchor
case *ImageAttributes:
t = Image
attr.NodeType = Image
case *ScriptAttributes:
t = Script
attr.NodeType = Script
case *DivisionAttributes:
t = Division
attr.NodeType = Division
default:
return nil, errors.WithStack(fmt.Errorf("unknown node type: %T", n.Attributes))
}
}
if n.Type == "" {
n.Type = t
} else if n.Type != t {
return nil, errors.WithStack(fmt.Errorf("node type and node attributes mismatch: %T != %s", n.Attributes, n.Type))
}
if n.Meta == nil {
n.Meta = new(Meta)
}
return json.Marshal((*jsonRawNode)(n))
}
View on GitHub (pinned to b86338da04)