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

  1. Use only the attribute structs the library defines (InputAttributes, TextAttributes, ImageAttributes, ScriptAttributes, AnchorAttributes, DivisionAttributes, ...).
  2. Check the %T value in the message to identify the unexpected attributes type you set.
  3. Remove custom attribute structs or add them to the MarshalJSON switch in a fork/patch.
  4. 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

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


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)