Found on a real isolated-posture dogfood boot (epic #12701 program, 2026-08-27). Small, one-line class of fix; the cost is real because the crash swallows the admission verdict the operator needs.
Measured
On the EE composed deployment (framework main, @objectstack/organizations runtime), every audience-gate refusal that routes through audienceLogError answers HTTP 500 with this in the server log:
ERROR [Better Auth]: TypeError: Cannot read properties of undefined (reading 'writeErrorLike')
at error (file:///.../packages/core/dist/index.js:650:10)
at _AuthManager.audienceLogError (file:///.../packages/plugins/plugin-auth/dist/index.mjs:5460:38)
The refusal it was trying to log (in our run: "the declared self-registration permission set '…' cannot be resolved") never reaches the caller or the log — the client sees 500 null, and the operator diagnoses blind.
Root cause (source-level)
packages/plugins/plugin-auth/src/auth-manager.ts:3499:
(logger?.error??logger?.warn)?.(message,meta);
The ?? expression extracts the method from the logger before calling it, so the call runs with this === undefined. A plain-closure logger (most test doubles) survives; @objectstack/core's class-based logger dereferences this.writeErrorLike inside error() and throws. That is why no suite caught it — the receiver-sensitive logger only appears in real compositions.
Fix shape: keep the fallback, keep the receiver — logger?.error ? logger.error(message, meta) : logger?.warn?.(message, meta) (or .call(logger, …)); a regression pin with a class-based logger double whose methods read this.
Same-pattern sweep suggestion: grep the repo for (logger?.error ?? logger?.warn) and sibling detach-then-call shapes — this one probably has family.
Found on a real isolated-posture dogfood boot (epic #12701 program, 2026-08-27). Small, one-line class of fix; the cost is real because the crash swallows the admission verdict the operator needs.
Measured
On the EE composed deployment (framework main,
@objectstack/organizationsruntime), every audience-gate refusal that routes throughaudienceLogErroranswers HTTP 500 with this in the server log:The refusal it was trying to log (in our run: "the declared self-registration permission set '…' cannot be resolved") never reaches the caller or the log — the client sees
500 null, and the operator diagnoses blind.Root cause (source-level)
packages/plugins/plugin-auth/src/auth-manager.ts:3499:The
??expression extracts the method from the logger before calling it, so the call runs withthis === undefined. A plain-closure logger (most test doubles) survives;@objectstack/core's class-based logger dereferencesthis.writeErrorLikeinsideerror()and throws. That is why no suite caught it — the receiver-sensitive logger only appears in real compositions.Fix shape: keep the fallback, keep the receiver —
logger?.error ? logger.error(message, meta) : logger?.warn?.(message, meta)(or.call(logger, …)); a regression pin with a class-based logger double whose methods readthis.Same-pattern sweep suggestion: grep the repo for
(logger?.error ?? logger?.warn)and sibling detach-then-call shapes — this one probably has family.