Summary

  • Early LDAP made the MessageID unique only among requests still in progress on one session. Every entry, reference and final result belonging to an operation echoed that ID, so asynchronous replies could interleave without becoming indistinguishable.
  • Abandon revealed the identifier's limit: its envelope had one ID while its payload named the target ID, yet neither the request nor a successfully abandoned search returned a completion response. RFC 3909 later added a response-bearing Cancel operation for applications that needed an outcome.
  • Paged search used a fresh message ID for each page and an opaque cookie for continuation. The ID named local work; it did not authenticate a peer, name a durable query or prove that a write had been reversed.

A search was never one reply

The lightweight in LDAP did not mean that every operation became a single question followed by a single answer. The protocol was designed as a less costly way to reach directory services built around the X.500 model. Once a client asked for a subtree, the useful answer might contain hundreds of directory entries, a reference to another naming context and only then a terminal result.

RFC 1487, published in July 1993, placed every operation inside a common LDAPMessage envelope. Its only shared field was messageID, an integer that had to differ from the IDs of other requests outstanding in the same LDAP session. The server copied that value into every response envelope corresponding to the request.

That wording gave the number a more interesting job than counting packets. A search returned zero or more entry responses and one final result. All of them belonged to one operation. If the number had changed with every response, the client would have needed another way to know which entries and terminal status formed one result stream.

The number did not describe the directory object. A distinguished name did that. It did not describe the operation's meaning; the protocol-operation tag did that. It supplied the missing join between an in-progress request and the messages produced on its behalf.

Interleaving made the scope visible

RFC 1777, the 1995 LDAP specification, said there was no requirement for synchronous behaviour: requests and responses for multiple operations could be exchanged in any order. A client could issue a quick comparison while a broad search was still returning entries. The server could answer the comparison before the search reached its final result.

The resulting wire sequence might read like this: search 41, compare 42, entry 41, compare result 42, another entry 41, final search result 41. TCP supplied reliable ordered bytes, but it did not say which application operation each encoded message served. MessageID performed that demultiplexing.

This is why the historical contract was session-local. The ID only needed to be different from other outstanding requests in that session. Another client could use 41. The same client could use 41 again after the earlier operation had unmistakably ended. Neither case created a collision because the comparison domain included the LDAP session and the operation lifetime.

RFC 2251 carried the mechanism into LDAPv3 in 1997. It bounded the integer at 2^31−1, noted that clients typically increment a counter and prohibited reuse before the final response. It also gave search replies distinct forms: SearchResultEntry and SearchResultReference could arrive in either order, followed by one SearchResultDone that carried success or error.

The terminal response therefore did two jobs. Its result code said how the search ended. Its arrival also gave the client ordinary evidence that the server no longer needed that operation's ID.

Zero was set aside for speech without a question

The 2006 revision reorganized LDAPv3. RFC 4510 records how the new specification set replaced RFC 2251; RFC 4511 contains the revised protocol rules.

RFC 4511 made request IDs explicitly nonzero. Zero was reserved for an unsolicited notification: a server-originated extraordinary message that did not answer a client request. A Notice of Disconnection could therefore arrive as message ID zero without being mistaken for the response stream of operation zero.

This was not a global namespace allocation. It was a locally enforceable partition. Positive IDs belonged to client-initiated work in progress; zero signalled a defined class of server speech outside that correlation. The protocol operation and notification object identifier still supplied the meaning.

Reuse remained tied to service lifetime rather than elapsed time. A client could reuse an ID only when it could determine that the server was no longer servicing the earlier request—for example, after the final response or a subsequent Bind completed. A timeout might justify closing the session or reconciling application state, but silence alone did not rewrite the server's state table.

Abandon needed two numbers and still could not report an outcome

LDAP's original escape hatch is a compact lesson in authority. An Abandon operation is itself an LDAP request, so its envelope carries a new MessageID. Its payload is also a MessageID: the earlier operation the client wants stopped. One number correlates the abandon request as an operation; the other selects its target.

There is no Abandon response. Under RFC 4511, the server may abandon the target. If the target is a search already emitting results, the server must stop sending further entry responses and must not send SearchResultDone. The client must nevertheless tolerate results already in transit, and some operations may not be abandoned at all.

The silence is deliberate but ambiguous. It avoids adding another response exchange to a request commonly used when the client no longer wants the result. It also means the client cannot tell a successful abandon from work that is still uncompleted. The shared ID can identify exactly which work was addressed without proving what the server did about it.

RFC 2251 reflected this uncertainty in its reuse rule: do not recycle either the Abandon request's ID or the target ID until a response arrives for a later request. That later response is not an acknowledgement of abandon. It is merely evidence that the server has progressed far enough on the connection to reduce one kind of collision risk.

Cancel added a result rather than pretending the old signal was stronger

RFC 3909, published in 2004, defined an LDAP Cancel extended operation for applications that require an indication of outcome. It did not change the meaning of Abandon. It introduced a separate mechanism.

A Cancel request has its own envelope MessageID and carries a cancelID naming the outstanding operation. If cancellation succeeds, the server returns a successful Cancel response and the target operation ends with result code canceled. Other results distinguish a target the server does not know, an operation that cannot be cancelled and a request that arrived too late.

The tooLate case matters. RFC 3909 uses an update already committed to the underlying data store as its example. Perfect correlation does not create rollback authority. The cancel ID may point at precisely the intended update while the only honest result is that its irreversible effect has already crossed the boundary.

Cancel also restricts what may be targeted. Bind, StartTLS, Unbind, Abandon and Cancel itself are not cancellable. Those operations create, change or tear down the association and security context in which ordinary operation IDs make sense. Letting one outstanding operation casually erase that context would turn a correlation key into a control it was never designed to hold.

A new page required a new ID

Search pagination provides the clearest negative proof. RFC 2696 lets a server return a page of results and an opaque cookie in SearchResultDone. To request the next page, the client repeats the search values but changes the messageID, supplies the latest cookie and may change the page size.

The next page is a new LDAP operation. The cookie carries the server's continuation state across those operations. An older cookie may be unusable; an empty cookie means the sequence is complete. Abandon can stop one page request in progress but may invalidate the cookie, while ending the paged sequence cleanly uses a new search request with size zero and the latest cookie.

This division prevents one convenient integer from acquiring mythical durability. The message ID answers, “Which in-progress operation on this session produced this message?” The cookie answers, “What server-held result position may this later operation resume?” A directory entry's distinguished name answers something else again.

The sources establish the rule, not present behaviour

The historical chain is closed to RFC 1487, RFC 1777, RFC 2251, RFC 2696, RFC 3909, RFC 4510 and RFC 4511. They establish protocol formats, normative boundaries and revision history. They do not measure deployment, certify an implementation or prove the outcome of a captured operation.

LDAP's small integer endured because its authority was narrow. It joined messages to state that a receiver could actually inspect. Whenever an application needed more—completion, cancellation, continuation, authentication or authorization—the protocol required different evidence.