DomainNegotiationContext::$domain starts as NULL and is only ever set by setDomain(), so everything that hands it back can return NULL: on the CLI, during cron, and whenever no domain matches the request. The class says so itself one method below the getter, where hasDomain() is $this->domain !== NULL.

Four docblocks claim otherwise:

  • DomainNegotiationContext::$domain, the property the rest of the chain returns.
  • DomainNegotiationContext::getDomain(), which returns that property directly.
  • DomainNegotiatorInterface::getActiveDomain(), which is what a consumer type hints against.
  • DomainSourcePathProcessor::getActiveDomain(), which reads the same context.

There is no behavior change and no signature change in fixing them. The callers in this project already treat the value as nullable, and DomainTestTrait::getActiveDomain() has documented it as nullable all along.

Why it matters to a consumer

A module running static analysis is told its null guard is dead code. Against domain 3.0.1 PHPStan reports instanceof.alwaysTrue on such a guard, and against the 3.x branch it does not: same consumer code, same PHPStan, different answer. Acting on that report by deleting the guard produces a fatal the first time the code runs on the CLI or against an unmatched host. This surfaced in Orchestra, whose DomainTenantResolver keeps the guard and had it reported as redundant only when CI resolved 3.0.1.

Branches

All three supported branches carry the same defect, and it is not the same subset on each, so this needs three merge requests rather than one plus a backport.

  • 3.0.x: all four were wrong. Fixed by !458, merged as 71ce3b1d.
  • 3.x: getActiveDomain() on the interface was already correct; the other three were not. !459.
  • 4.x: identical to 3.x, same three. !460.

The interface method was corrected on 3.x and 4.x some time ago, which is what made this look branch-specific at first: the fix stopped at the method a consumer type hints against and did not follow the value back to the property it comes from.

AI-Generated: Yes (Claude Code was used to help draft this issue summary and to write the docblock corrections on the merge request. I reviewed them and checked each claim against the 3.0.x and 3.x branches before posting.)

Issue fork domain-3619901

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mably created an issue. See original summary.

mably’s picture

mably’s picture

Title: DomainNegotiatorInterface::getActiveDomain() is documented as returning a DomainInterface, but returns NULL whenever nothing is negotiated » Document the negotiated domain as nullable, because it is NULL until something negotiates one
Issue summary: View changes
Status: Active » Needs review

  • mably committed 71ce3b1d on 3.0.x
    fix: #3619901 Document the negotiated domain as nullable, because it is...
mably’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

mably’s picture

Issue summary: View changes
Status: Fixed » Needs review

  • mably committed 2bfe5193 on 4.x
    fix: #3619901 Document the negotiated domain as nullable, because it is...

  • mably committed 5e0821a9 on 3.x
    fix: #3619901 Document the negotiated domain as nullable, because it is...
mably’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.