AWRA OpsHub Search

One Address, Four Places It Could Already Be

An email address can be an organisation owner, a staff account or a supplier login, and it cannot be two of them. The check that enforces that is deliberately unscoped — and the reason is that its failure direction points the wrong way.

Security & Compliance AWRA OpsHub Team 11 min read

A guard that returns "nothing found" when it cannot look is not a guard that failed. It is a guard that started approving everything.

An email address is the closest thing this product has to a universal identifier for a person. It is how somebody signs in, how a password reset reaches them, how a supplier is recognised. So the same address cannot belong to two different kinds of identity at once, and there is one check that establishes it.

Four places an address might already be

Where What it means What the message says
A user account Somebody who signs in to a workspace Already used by a user account — use a different one, or update the existing user.
An organisation owner The account that owns a workspace Belongs to an organisation owner account — use the owner login, or choose a different address.
A supplier portal login A credential issued to a supplier Already used for a supplier portal login — update the supplier account first.
A supplier record The supplier itself, whether or not a login exists Already used by a supplier record — update the existing supplier.

The first match wins and the message names which. That matters: "this email is taken" is unactionable, and "this email belongs to an organisation owner account — use the owner login" tells somebody exactly what to do next. The four messages are different for that reason.

Customers are deliberately not on the list

A customer record carrying an email address does not conflict with anything, because a customer is not an identity — there is no customer login, and the address is a way of reaching them rather than a way of being them. So the same person can be a customer of your business and a staff member of another workspace without either fact interfering with the other. That is correct, and it is the reason the list is four items rather than six.

Why the check ignores which organisation is asking

The question is whether this address is used anywhere at all, not whether it is used in your workspace. An address belonging to a supplier login in another organisation is still an address that cannot become a user account here, because signing in has to resolve to exactly one identity.

So the whole scan runs explicitly outside the usual organisation boundary. That declaration is the interesting part, and it is worth understanding why it is stated rather than assumed.

A scoped question would have a scoped answer, and the answer would be wrong.

The failure direction

Record lookups in this product are scoped to an organisation by default, and when there is no organisation to scope to, they return nothing rather than everything. That is the right default and it is a security property: a request that cannot establish whose data it is asking for should not receive all of it.

Now apply that to this check. It runs during public signup, where there is no signed-in organisation. Scoped, each of the four lookups returns no rows. No rows means no match. No match means no conflict. And no conflict means the registration proceeds.

  1. The guard does not error

    Nothing throws, nothing is logged as a failure, and the signup screen behaves normally.

  2. It returns the permissive answer

    The absence of a conflict is indistinguishable from the absence of a look. Both are null.

  3. And the symptom is a duplicate identity

    A registration completes with an address that already belongs to a supplier portal login — discovered later, by somebody who cannot sign in, or who signs into the wrong thing.

That combination — a security default that is correct in general, applied to a check whose safe answer is the opposite of its empty answer — is one of the more instructive failure shapes in software. The default is not wrong. The check is not wrong. What is wrong is inheriting the default silently in a place where the empty result means "allow".

The general rule

When a lookup fails or is prevented, ask what its empty result means to the caller. If empty means refuse, a failure is safe and the worst case is an inconvenience. If empty means allow, a failure is an outage of the control with no symptom, and the lookup has to be either explicitly authorised or explicitly checked for having run.

Empty means "refuse"

A failure is safe

A permission check that finds no grant refuses. If it cannot look, it also refuses. Nothing is lost but access, and somebody complains immediately.

Empty means "allow"

Declare the access, or check that it ran

A uniqueness check, a blacklist, a duplicate detector. All of them treat "found nothing" as permission, so all of them need to distinguish that from "could not look".

You are not sure which

Write the empty case down

It is a one-line comment and it is the single most useful thing anybody can leave beside a guard. The next reader will otherwise have to derive it from three call sites.

Scope, not a ceiling

Around identity conflicts

The check itself is correct and explicitly scoped. What organisations ask for is help resolving a conflict once it has been reported, rather than being told to choose a different address.

A resolution path

Where an address genuinely belongs to the same person in two roles, a supported way to link or migrate rather than an instruction to use a different address.

Conflict reporting for administrators

A view of addresses that would conflict, run before an import rather than discovered one row at a time during it.

A ran-or-not assertion

A check that distinguishes "found nothing" from "could not look", so a guard whose empty answer means allow can never quietly stop looking.

We publish scope, not dates.

Scope identity handling

The identity ledger, precisely

What AWRA OpsHub does today

  • A single check establishing whether an email address is already used as a user account, an organisation owner account, a supplier portal login or a supplier record.
  • A distinct, actionable message per source, naming what the address already is and what to do about it.
  • The whole scan declared to run outside the organisation boundary, because the question is whether the address is used anywhere rather than whether it is used here.
  • An exception list, so a check performed while editing an existing record can skip the record it is about.
  • Addresses lowercased and trimmed before comparison, so case and stray spaces do not create a second identity.
  • An empty address treated as no conflict rather than as a match, so an optional field does not block a form.
  • Customer records deliberately excluded, because a customer is a party you correspond with rather than an identity that signs in.

More we can add to your workspace

  • A supported path to link the same person in two roles, for the genuine case where a staff member is also a supplier contact.
  • A conflict report before an import, listing the addresses that would clash so a bulk load can be corrected in one pass.
  • An assertion that the check actually ran, distinguishing a clean result from a lookup that could not happen.
  • Employee records included in the scan, where an organisation treats an employee record as an identity rather than as a personnel file.
  • A record of rejected registrations by conflict source, which would show whether a signup path is being met by the same collision repeatedly.
  • Alternative-address suggestion, offering a workable variant rather than only refusing.

Where we point you to a specialist

  • We will not let one email address resolve to two identities that can sign in. Authentication has to produce exactly one answer to "who is this", and an address that could be a staff account or a supplier login depending on the door is an ambiguity that eventually authenticates the wrong one.
  • We will keep the scan explicitly cross-organisation. The answer to "is this address used anywhere" cannot be scoped without becoming a different and misleading answer, and stating the access is what stops a general security default silently disarming it.
  • Deciding whether a person in two roles should hold one address or two is your operational choice. We will refuse the ambiguity and describe it precisely; how you arrange your own people's addresses is not ours to prescribe.

A conflict report before an import is the contained piece with the clearest value, because the worst version of this problem is a bulk load discovering the same class of collision three hundred times, one row at a time.

Our take

The check is unremarkable and the lesson attached to it is not. Uniqueness guards, blacklists, duplicate detectors and rate limiters all share a property that permission checks do not: their empty answer is permission. That makes them uniquely dangerous under a security default that returns nothing when it cannot establish context — the default is correct, the guard is correct, and together they produce a control that reports success while doing nothing at all. The fix here was to state the access explicitly, with the reason written beside it. The habit worth taking away is smaller and more general: beside any guard, write down what an empty result means. If it means allow, the guard needs to know the difference between finding nothing and not looking.

Five questions to ask about identity uniqueness

Where is an address checked against?

A good answer sounds like

A named list.

What ours actually is

User accounts, organisation owner accounts, supplier portal logins and supplier records. Four sources, checked in that order.

Is the check limited to my organisation?

A good answer sounds like

No, with a reason.

What ours actually is

No, deliberately — the question is whether the address is used anywhere, and a scoped version would answer a different question.

What does a conflict tell the person?

A good answer sounds like

Something actionable.

What ours actually is

Which kind of record already holds it and what to do — use the owner login, update the supplier first, and so on.

Do customer records conflict?

A good answer sounds like

A reasoned answer.

What ours actually is

No. A customer is a party you correspond with rather than an identity that signs in, so the same address can be a customer here and a user elsewhere.

What happens if the check cannot run?

A good answer sounds like

It must not silently allow.

What ours actually is

This is exactly the failure it is written to avoid — the empty result means no conflict, so the access it needs is declared explicitly rather than inherited.

Audit your own permissive guards

Find the checks in your system whose empty answer means yes. There are always more than you expect, and they are the ones where a lookup that stops working produces no symptom at all.

Talk through identity handling

Frequently asked questions

Why can the same email not be a user and a supplier login?

Because signing in has to resolve to exactly one identity. An address that could be a staff account or a supplier portal login depending on which door was used is an ambiguity, and ambiguities in authentication eventually resolve the wrong way. The refusal names which of the four kinds of record already holds the address so the person can act on it.

Our supplier contact is also on our staff. What do we do?

Today, two addresses. The check refuses the ambiguity rather than resolving it, which is the safe answer and not the convenient one. A supported way to link the same person across two roles is the first item on the list above, and it is the situation that raises this question most often.

Does a customer record block an address?

No. Customers are deliberately outside the check, because a customer is not an identity that signs in — the address is how you reach them rather than how they authenticate. So somebody can be your customer and a user of another workspace with the same address, and neither fact interferes with the other.

Why does the check ignore the organisation?

Because "is this address used anywhere" is the question that matters, and a version scoped to one organisation would answer something else while looking identical. An address belonging to a supplier login in another workspace still cannot become a user account here.

What was the actual bug?

A registration completing with an address that already belonged to a supplier portal login. Scoped lookups during public signup — where no organisation is established — returned no rows, no rows read as no conflict, and no conflict read as permission. Nothing errored and nothing was logged, which is why it presented as a duplicate identity rather than as a failure.

How would I find this class of problem elsewhere?

Look for guards whose empty result means allow: uniqueness checks, blacklists, duplicate detection, anything that permits when it finds nothing. Then ask what happens to each of them when the lookup underneath cannot run. Permission checks are safe under the same conditions because their empty result means refuse — which is why this shape is easy to miss when you have been reasoning about permissions.

Help Center

Need a quick answer while you read?

Run inventory, procurement, assets, sales, and field work with approved AWRA guidance for setup, migration, integrations, security, pricing, and support.

Search all approved AWRA public help articles.

Open Help Center