zitadel/zitadel · error · Internal

QUOTA-8YXPk

QUOTA-8YXPk

Error message

sorting slices of *quota.SetEventNotification with nil pointers is not supported

What it means

This internal error is thrown by sortSetEventNotifications in internal/command/quota_model.go when a *quota.SetEventNotification element in the slice being sorted is nil. The comparator cannot safely dereference nil pointers to compare Percent/CallURL/Repeat, so it aborts the sort with a zerrors internal error (code QUOTA-8YXPk). It is a programming/invariant error, not an expected runtime condition.

Source

Thrown at internal/command/quota_model.go:171

	for idx, notification := range q {
		notifications[idx] = &quota.SetEventNotification{
			Percent: notification.Percent,
			Repeat:  notification.Repeat,
			CallURL: notification.CallURL,
		}
		notifications[idx].ID, err = idGenerator.Next()
		if err != nil {
			return nil, err
		}
	}
	return notifications, nil
}

// sortSetEventNotifications reports an error if there are duplicate notifications or if a pointer is nil
func sortSetEventNotifications(notifications []*quota.SetEventNotification) (err error) {
	slices.SortFunc(notifications, func(i, j *quota.SetEventNotification) int {
		if i == nil || j == nil {
			err = zerrors.ThrowInternal(errors.New("sorting slices of *quota.SetEventNotification with nil pointers is not supported"), "QUOTA-8YXPk", "Errors.Internal")
			return 0
		}
		if i.Percent == j.Percent && i.CallURL == j.CallURL && i.Repeat == j.Repeat {
			// TODO: translate
			err = zerrors.ThrowInternal(fmt.Errorf("%+v", i), "QUOTA-Pty2n", "Errors.Quota.Notifications.Duplicate")
			return 0
		}
		if i.Percent < j.Percent ||
			i.Percent == j.Percent && i.CallURL < j.CallURL ||
			i.Percent == j.Percent && i.CallURL == j.CallURL && !i.Repeat && j.Repeat {
			return -1
		}
		return +1
	})
	return err
}

View on GitHub (pinned to 13948f2bcd)

Solutions

  1. Filter nil entries from the Notifications slice before passing quota to the command: notifications := slices.DeleteFunc(notifs, func(n *quota.SetEventNotification) bool { return n == nil })
  2. Ensure every notification in the quota config is fully initialized (non-nil) when constructing quota.SetQuota
  3. If a nil means 'no notification', omit the entry rather than including a nil pointer
  4. If the error surfaces from deserialized config, fix the decoder/marshaling so empty entries become nil-free slices

Example fix

// before
quota.Notifications = []*quota.SetEventNotification{emailNotif, nil, logNotif}
// after
quota.Notifications = []*quota.SetEventNotification{emailNotif, logNotif}
Defensive patterns

Strategy: validation

Validate before calling

if slices.ContainsFunc(notifications, func(n *quota.SetEventNotification) bool { return n == nil }) {
    return errors.New("quota notifications must not contain nil entries")
}

Type guard

func validNotifications(ns []*quota.SetEventNotification) bool {
    return !slices.ContainsFunc(ns, func(n *quota.SetEventNotification) bool { return n == nil })
}

Prevention

When it happens

Trigger: Calling AddQuota/SetQuota (quota instance or org setup) with a Notifications slice that contains at least one nil *quota.SetEventNotification element; the nil element is hit when slices.SortFunc invokes the comparator.

Common situations: Building quota config programmatically where a notification entry failed to initialize or an optional notification was left nil instead of omitted from the slice; JSON/YAML config decoding that produced nil slice entries.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of zitadel/zitadel@13948f2bcd (2026-09-06). Data as JSON: /api/errors/bba109efd8ba7041. Report an issue: GitHub.