nats-io/nats-server · error

DN ended with incomplete type, value pair

Error message

DN ended with incomplete type, value pair

What it means

Returned by consumerMemStore.Update when AckFloor.Stream exceeds Delivered.Stream. Stream-wise ack floor must always be <= delivered stream sequence; a state violating this is rejected outright. Same invariant family as the consumer ack floor check, but on the stream sequence namespace.

Source

Thrown at internal/ldap/dn.go:208

				rdn.Attributes = make([]*AttributeTypeAndValue, 0)
			}
		case char == ' ' && buffer.Len() == 0:
			// ignore unescaped leading spaces
			continue
		default:
			if char == ' ' {
				// Track unescaped spaces in case they are trailing and we need to remove them
				unescapedTrailingSpaces++
			} else {
				// Reset if we see a non-space char
				unescapedTrailingSpaces = 0
			}
			buffer.WriteByte(char)
		}
	}
	if buffer.Len() > 0 {
		if len(attribute.Type) == 0 {
			return nil, errors.New("DN ended with incomplete type, value pair")
		}
		attribute.Value = stringFromBuffer()
		rdn.Attributes = append(rdn.Attributes, attribute)
		dn.RDNs = append(dn.RDNs, rdn)
	}
	return dn, nil
}

// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch).
// Returns true if they have the same number of relative distinguished names
// and corresponding relative distinguished names (by position) are the same.
func (d *DN) Equal(other *DN) bool {
	if len(d.RDNs) != len(other.RDNs) {
		return false
	}
	for i := range d.RDNs {
		if !d.RDNs[i].Equal(other.RDNs[i]) {
			return false

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Fix the code advancing the ack floor so it never exceeds delivered stream sequence
  2. Clamp AckFloor.Stream to Delivered.Stream before Update
  3. Re-derive state from stored message sequences if it came from a suspect source

Example fix

// before
st.AckFloor.Stream = 500; st.Delivered.Stream = 400
consumer.Update(st)
// after
if st.AckFloor.Stream > st.Delivered.Stream {
    st.AckFloor.Stream = st.Delivered.Stream
}
consumer.Update(st)
Defensive patterns

Strategy: validation

Validate before calling

if st.AckFloor.Stream > st.Delivered.Stream {
    st.AckFloor.Stream = st.Delivered.Stream // clamp
}
consumer.Update(st)

Try / catch

if err := consumer.Update(st); err != nil {
    if strings.Contains(err.Error(), "bad ack floor for stream") {
        st.AckFloor.Stream = st.Delivered.Stream
        err = consumer.Update(st)
    }
}

Prevention

When it happens

Trigger: Calling consumerMemStore.Update(state) where state.AckFloor.Stream > state.Delivered.Stream.

Common situations: Restoring/migrating consumer state from a snapshot with mismatched sequences; concurrent updates applied out of order; bugs in ack-floor advancement logic.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/4ca33fe5d6988743. Report an issue: GitHub.