Reference Lookups

How a reference is looked up: the three lookups behind a reference field, what every answer means, the five failure states and whose problem each one is, what happens when the referenced record is deleted, and how the picker behaves.

A reference field is drawn by three separate lookups: one asks which kinds of record you may point at, one searches a chosen kind, and one resolves a pointer you already hold back to a name. This page covers all three, every answer each one can give, and — the part worth reading before anything goes wrong — what each different kind of failure means and who can fix it.

The three lookups

All three live under one address of their own rather than alongside the other custom-fields calls, and that is deliberate: these read other modules' data, so they are guarded by the target kind of record's own view permission and not by the permission to administer field definitions. Somebody who administers custom fields but may not read staff is refused here, correctly.

MethodEndpointDescriptionAuth
GET/api/v1/entity-lookup/typesLists the kinds of record this caller may point at right now.🔒 Required
GET/api/v1/entity-lookup/{entityTypeKey}Returns one page of selectable records of one kind, optionally filtered.🔒 Required
GET/api/v1/entity-lookup/{entityTypeKey}/{entityId}Resolves one pointer the caller already holds back to its record.🔒 Required

So there is no single permission that opens this feature. All three require you to be signed in as an administrator, and each then requires the view permission for the kind of record in the address: listing staff members needs the staff view permission, listing user accounts needs the one for user accounts. The consequence to expect is that the same person can be admitted by one of these lookups and refused by the next, on the same screen, and both answers are correct.

Listing what you may point at

This answers with the filtered set, not the full catalogue: registered, answerable by this installation, and permitted for you. Every entry it returns is usable immediately, which is the whole reason it exists — a control that offered every registered kind of record would be offering choices that refuse you on the next click, and the alternative of trying each one in turn is a fistful of denials per page load.

An empty list is a success, not a failure. It means "you may not point a reference at anything", and it is rendered as an explanatory sentence inside the control rather than as an error or as a silently empty dropdown. It has two possible causes and the product names both without asserting either: the owning modules may not be part of this installation, or you may not hold view access to them. Only the second is fixed by asking for permissions, which is why copy naming one cause would send somebody to do something that cannot work.

Each entry carries its stable identifier, the module that owns it, and a display name in English and Arabic. Those names come from the platform's own registry rather than from this application's translations, so they are shown as supplied and never looked up as translation keys.

Searching one kind of record

One page of selectable records, in a stable order, with an optional free-text filter. Which columns the filter matches is the owning module's choice rather than a promise made here.

A page holds twenty rows by default. Asking for more than a hundred is silently capped rather than refused, and the order is stable across calls on purpose — an unstable order makes page two return rows you already saw on page one. The control loads the first page, then accumulates further pages behind a Load more control rather than replacing what you were looking at.

Each row carries a display name that is never blank, an optional second line to tell two similarly named records apart, and a flag saying whether the record is dormant. Deleted records are not returned at all, so that flag never means deleted — a dormant row is present, selectable, and a perfectly valid answer.

Typing is debounced before it becomes a request. Without that, an eight-character name would fire eight cross-module queries, seven of whose answers are thrown away — and the one that renders would be whichever returned last rather than the one matching what you typed.

Resolving a pointer you already hold

The read half of the feature, and the only way a stored reference ever becomes a name on screen. It takes the kind of record and the identity, and returns exactly the same shape a picker row has — so a reference loaded from the database and a record you just picked are drawn from one contract rather than two.

It applies every gate the search applies: the kind of record must be registered, you must hold that kind's own view permission, this installation must be able to answer for it, and the record is read through the owning module's workspace-filtered and deleted-record-filtered repository. Nothing about this being a display-only read relaxes any of them.

It is also the only place a name comes from. Nothing about a stored reference includes a name, by design, so a field that cannot resolve shows a specific sentence about why — never a name it remembered from earlier.

What each answer means

The answers are deliberately distinguishable from each other, with exactly one merge preserved. Read this table as the map from what the product tells you to what you should do about it.

AnswerWhat it meansWhose problem it is
SuccessThe record resolved. You get its current name, its optional second line, and whether it is dormant.Nobody — this is the normal case.
Not permittedYou do not hold the view permission for that kind of record. This says nothing whatsoever about the record, or about whether it still exists.Whoever administers roles. It is a fact about your own access, and you could already have learnt it by reading your own permissions.
Not foundThe record does not resolve. It was deleted, or it belongs to a workspace you cannot see — merged into one answer on purpose so this lookup cannot be used to test what exists elsewhere.Whoever owns the data. Pick a different record, or clear the field.
Unknown record typeThe kind of record named is not registered at all. This describes the installation, not any record — it usually means a field was pinned to a kind of record that has since been retired.Whoever administers the deployment.
Module not availableThe kind of record is registered but the module that owns it is not part of this installation, so nothing here can answer for it. No permission grant will ever change this.Whoever administers the deployment.
Invalid identityThe identity sent could not be read at all. Either it was altered on its way through something, or a stored value predates a change and can no longer be interpreted.Whoever is filling the record in — pick the record again. This one is replaced, never re-pointed.

The five failure states, and why they read differently

A reference field can fail to display for five distinct reasons. They are five different sentences on screen because they are five different problems with five different remedies, and this is the single most important table on this page.

What has happenedWhat the field says and doesWhat to do
You may not view that kind of recordThe field states that the stored value is fine but that its name cannot be shown to you, and becomes read-only — readable, with no picker. It is deliberately not blanked, because blanking it would invite somebody with no visibility into the target to overwrite a perfectly good reference.Nothing about the data. Ask whoever administers roles for view access to that kind of record.
The referenced record no longer existsThe field states that the record cannot be found, offers both possible reasons — deleted, or in an organisation you cannot see — and claims neither. It stays editable.Pick a different record, or clear the field. Re-picking is the fix.
The stored reference is malformedThe field states that what is stored cannot be read at all, stays editable, and additionally marks itself as invalid — because unlike a dangling pointer this is not a value the product ever legitimately produced.Pick the record again. This one has to be replaced rather than re-pointed, and it is worth reporting if you did not cause it.
The lookup could not run just nowThe field states that it could not load the referenced record at the moment and that the reference itself is fine, and offers a Try again control.Try again. Emphatically do not clear the field — the stored value is good, and clearing it is the one action that turns a passing failure into real data loss.
This installation cannot answer for that kind of recordThe field states that this kind of record is not available in this installation, and offers no Try again control — because retrying will refuse identically every time.Ask whoever administers the deployment which kinds of record this installation can use. This is an installation matter, not a permission one.

What is checked when a reference is saved

Every reference save runs the same checks in the same order, and each one fails with its own message rather than a generic "invalid reference". Knowing the order explains every refusal you can hit.

  1. Both pieces present. A submission missing either the kind of record or the identity is refused as an incomplete reference — never treated as an empty field, because half a reference means somebody started answering and stopped.
  2. The kind of record is registered. An unregistered identifier has no permission behind it, so there would be nothing for the later checks to check against. Refused, naming the identifier.
  3. The kind of record is allowed for this value type. Always true for Entity Reference; for User Reference this is the fixed platform allowlist, and the refusal names what is allowed rather than only that your choice was not.
  4. The kind of record agrees with the definition's pin, if there is one. Refused naming both what was expected and what arrived. An unpinned definition skips this check entirely — unpinned means "any allowed kind", and must never be read as "nothing configured, therefore nothing valid".
  5. The identity can be read. A stale or altered identity is refused cleanly as an invalid identity, on that one field, rather than failing the whole save with an unexplained error.
  6. You could read that record right now. This is the check that makes everything else safe, and it is deliberately a single flat refusal with no detail — see below.

That last check holds you to the target kind of record's own view permission and resolves the record through the owning module's workspace-filtered repository. Without it the feature would be an extraction tool rather than a reference: somebody who may edit an administrator record but may not read staff could store an arbitrary staff identity and then read the name back through the resolve lookup. Storing a pointer at data is a read of that data, deferred.

One detail with a real consequence: the answer stores the kind of record the value actually points at, never the definition's pin. The two are equal at the moment of saving precisely because of the fourth check — but writing the pin instead would silently rewrite the meaning of every stored answer the day somebody re-points the field, which is the one property that keeps an old answer readable.

When the referenced record is deleted

Deleting a record that other records point at is a normal operation and needs no clean-up. The pointers clear themselves.

  1. The record is deleted, in the ordinary way

    Somebody deletes the staff member, the user account or the person through that module's own screen, holding that module's own delete permission. Nothing about custom fields is involved yet.
  2. The deletion records that it happened

    The delete and the note saying it happened are committed together, in one transaction. Either both happen or neither does, so there is no window in which a record is gone but nothing recorded the fact.
  3. Every pointer at that record is cleared

    Both pieces of each affected answer are cleared together, in the same pass. Never one without the other — half a reference is the one state nothing can display and no operator can repair.
  4. The value row survives

    Nothing is deleted. Each answer keeps its row, its version, its place in the record's set of answers and its audit trail. Only the pointer goes, which is why the field reads afterwards as genuinely empty rather than as broken.

The clearing covers both places answers are stored, including the older store still holding pre-migration answers, and it covers deleted answer rows too — a deleted row still holding a stale pointer would hand that stale pointer back to anybody who later restored it.

Clearing a pointer that is already clear does nothing, deliberately, so the operation is safe to repeat. The record's own snapshots of earlier answers are not swept, and do not need to be: they are short-retention rollback artefacts that are removed on their own schedule and are never a live display path in the meantime.

How the picker behaves

Details of the control itself that are easier to read once than to work out from its behaviour.

BehaviourWhy it is that way
Nothing is fetched until you open the control.A record form can carry several reference fields. One nobody touches should not query another module at all, and the answers are cached afterwards, so re-opening the control costs nothing.
An unpinned field shows two controls, and neither steals focus from the other.Choosing a kind of record leaves you on that control with the record control now available one step away. Automatically opening the record picker would pull focus out from under somebody still reading what they just chose.
Further pages add to the list rather than replacing it.A search over a whole workspace's staff table needs paging, and a list that replaced itself would lose the row you scrolled past on your way to Load more.
A dormant record is marked, not hidden.It still exists and is still a valid answer — a departed staff member kept for historical assignments is exactly the case. Treating it as invalid would make historical references unsavable.
An unmatched filter and an empty list read differently."Your filter matched nothing" is about what you typed. "There is nothing you may point at" is about your access. One sentence for both would tell somebody who mistyped that they have no permissions.
Two of the failure states offer no Try again control.A permission refusal and an unavailable module refuse identically every time. A button inviting you to hammer them would be worse than no button. Only a genuine transport failure gets a retry, because that is the one a retry fixes.
In view mode the control is disabled rather than merely unclickable.A reference picker is a picker, so it follows the same convention every other picker on these forms follows. Its own read-only state, used when you may not view the target's name, is a different thing and looks different.
The control names itself for assistive technology.Its visible label is real, clickable wiring, but the accessible name is set on the control directly — a label alone cannot name a control of this shape. Two reference fields on one form therefore announce distinctly rather than both announcing as "Record type".

Diagnosing a reference that will not display

In order. Each step rules out one of the five states above, and the first four need no access you do not already have.

  1. Read the sentence in the field

    The five states never share wording, so the field has already told you which one you are in. This step is listed first because it is the one most often skipped.
  2. If it offers Try again, use it

    Only the transient failure offers one. If the field resolves on the second attempt, nothing was ever wrong with the stored value and there is nothing to fix.
  3. Check the same field on another record

    If every reference of that kind fails identically, it is your permissions or the installation — not the data. If only this one fails, the record it points at is the thing to look at.
  4. Have somebody with full access open the same record

    If they see a name and you do not, it is a permission on that kind of record. If they see the same failure, it is the data or the installation.
  5. Only then decide whether to re-pick or clear

    Re-pick when the record is genuinely gone or the stored value is malformed. Clear only when the field should be empty. Never clear a field that reported a transient failure — that is the one action that converts somebody else's outage into your data loss.

Limits and deliberate gaps

Stated so nobody spends an afternoon looking for a setting that is not there.

LimitDetail
Records per page in the pickerTwenty by default. A request for more than a hundred is capped rather than refused, and the cap is applied twice on the way in.
Delay between typing and searchingA fixed short pause, the same one every server-backed picker in the product uses. Not configurable.
No stored display nameThere is no setting anywhere to snapshot a name alongside a pointer, and there will not be one — it would hand a name guarded by one permission to anybody holding another.
No "what points at this record" viewNothing lists the references pointing at a given record. Deleting a record does not warn you how many pointers it is about to clear.
Not in the definitions exportThe eighteen-column definitions spreadsheet has no column for a pinned target type, so an exported definition does not record what its field points at.
One pointer per fieldThere is no multi-value reference type. Two answers means two fields.
The picker cannot be narrowed by anything but textWhich columns the free-text filter matches is the owning module's choice, and there are no additional filters — no "active only", no filter by group.
User Reference still refuses an administrator, even though Entity Reference no longer doesNot from the definition form and not from a request that bypasses it. User Reference's allowed target is exactly one thing, identity.user, by original design — an administrator's own record is a different kind of row, and pointing a User Reference field at one is refused regardless of which module the request came through. Entity Reference has offered administrators as a target since a later release added a lookup provider for them; this limit is User Reference's alone.

Where to go next

The concepts behind these lookups are on the Reference Fields page.

PageWhat it covers
Reference FieldsWhat the two reference types are, which to use, what is stored, why no name is kept, pinning a target type, what may be referenced, and the workspace rules.
Field-Level SecurityThe separate mechanism for hiding a whole field from a role or user group — which is a different thing from not being allowed to read a reference's target.
Limits and BehavioursEvery fixed cap and deliberate limitation across the whole feature, references included.