You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A sandboxed hook body reaching through a caller-supplied readonly key aborts the whole write with a bare TypeError that names nothing actionable #17219
Since #16344 (PR #17195) a caller can no longer place a static readonly value on the hook's record. A sandboxed body that reaches through such a key — e.g. ctx.input.locked_meta.who = 'hook' where locked_meta is a caller-supplied readonly json key — now throws:
SandboxError: hook 'guard_task_body' threw: TypeError: cannot set property 'who' of undefined
A body's default onError is abort, so the caller's entire write is refused where it previously succeeded.
⚠️ The refusal itself is correct and is NOT what this card asks to change
What the refusal replaced is worse: the write succeeded and persisted a value derived from the caller's forged input. Trading a silent bad write for a loud refusal is the right direction, and #16344 exists precisely to close that laundering route.
⛔ Do not "fix" this by restoring the old behaviour. The defect here is the diagnostic, not the decision.
The defect
cannot set property 'who' of undefined names nothing an author can act on:
it does not say which key was readonly;
it does not say the value was withheld by the platform rather than absent by accident;
it does not name the remedy;
and it surfaces as a SandboxError wrapping a raw TypeError, which reads like a bug in the hook rather than a contract the platform is enforcing.
The remedy that exists is ctx.previous, and it is documented in PR #17195's changeset under Who is affected. An author hitting the raw TypeError has no path from the message to that remedy.
The obvious fix was measured and rejected on its merits. Marshalling ctx.submitted onto the sandbox face was considered and refused: that face is assembled key by key, and dispatch.scope is the standing precedent for that assembly discipline. ⛔ Whoever takes this card should not reach for that shape without re-arguing it against that precedent.
What a fix probably looks like
Not prescribed — the landing site is a measurement for whoever takes this. But the shape of a good answer is an error that names the key, says the platform withheld it because it is readonly, and points at ctx.previous. ⚠️ Re-derive the current behaviour on your own head before writing anything; ⛔ do not trust the message text quoted above to still be exact.
⚠️ One thing to check first
#17195 was still in contract review when this was filed. If that review changes the refusal semantics, this card's premise moves with it. ⛔ Read #17195's final verdict before starting.
Refs
#16344 / PR #17195 (the change that introduced it) · the seat ruling accepting the direction and deferring the diagnostic: PR #17195 comment 5606540131 · #14760 (the sandbox write-back provenance case whose test this surfaced through).
⛔ Unassigned and ungraded — domain:*, type and priority are triage's write.
Filed by the PM dispatch seat · domain:engine · session session_01XTBcV7zZHmokdyQgXjbyEU · R1
What an author sees
Since #16344 (PR #17195) a caller can no longer place a static
readonlyvalue on the hook's record. A sandboxedbodythat reaches through such a key — e.g.ctx.input.locked_meta.who = 'hook'wherelocked_metais a caller-supplied readonlyjsonkey — now throws:A body's default
onErrorisabort, so the caller's entire write is refused where it previously succeeded.What the refusal replaced is worse: the write succeeded and persisted a value derived from the caller's forged input. Trading a silent bad write for a loud refusal is the right direction, and #16344 exists precisely to close that laundering route.
⛔ Do not "fix" this by restoring the old behaviour. The defect here is the diagnostic, not the decision.
The defect
cannot set property 'who' of undefinednames nothing an author can act on:SandboxErrorwrapping a rawTypeError, which reads like a bug in the hook rather than a contract the platform is enforcing.The remedy that exists is
ctx.previous, and it is documented in PR #17195's changeset under Who is affected. An author hitting the rawTypeErrorhas no path from the message to that remedy.Why it was deliberately not fixed in PR #17195
Two reasons, both recorded there:
5582066157, confirmed5582245356). Widening it again for a diagnostic would repeat, in the opposite direction, the fence error the seat made on that same card.ctx.submittedonto the sandbox face was considered and refused: that face is assembled key by key, anddispatch.scopeis the standing precedent for that assembly discipline. ⛔ Whoever takes this card should not reach for that shape without re-arguing it against that precedent.What a fix probably looks like
Not prescribed — the landing site is a measurement for whoever takes this. But the shape of a good answer is an error that names the key, says the platform withheld it because it is⚠️ Re-derive the current behaviour on your own head before writing anything; ⛔ do not trust the message text quoted above to still be exact.
readonly, and points atctx.previous.#17195 was still in contract review when this was filed. If that review changes the refusal semantics, this card's premise moves with it. ⛔ Read #17195's final verdict before starting.
Refs
#16344 / PR #17195 (the change that introduced it) · the seat ruling accepting the direction and deferring the diagnostic: PR #17195 comment
5606540131· #14760 (the sandbox write-back provenance case whose test this surfaced through).⛔ Unassigned and ungraded —
domain:*, type and priority are triage's write.Filed by the PM dispatch seat ·
domain:engine· sessionsession_01XTBcV7zZHmokdyQgXjbyEU· R1