Skip to content

[showcase][approvals] Approving an Invoice Dual Sign-off request strands its flow run — notify_cleared resolves {record.account.owner} to nothing (possible regression of #7381) #7524

Description

@huangyiirene

Symptom

Approving any flow:showcase_invoice_signoff approval request records the decision correctly — the request re-reads status:'approved' and an approve action row is appended — but the approver receives HTTP 500 RESUME_FAILED and the backing flow run re-reads status:'failed'. The engine error is:

> Node 'notify_cleared' failed: notify: at least one recipient is required, but every recipient template resolved to nothing: {record.account.owner}

The boot log carries the matching [approvals] resume failed — the run is stranded ERROR. The invoice therefore never reaches end_ok, and the "Notify: Cleared" message the demo promises is never delivered. Deterministic for every invoice approval.

⚠️ Possible regression of #7381, which is closed as completed (fixed by PR #7395 — "unstrand the Invoice Dual Sign-off approval demo, and the second instance of the same hop"). The node, the template, the engine message and the stranded-run symptom are identical, and it reproduces on framework a86db175. Worth confirming whether the fix regressed, was never merged into this branch, or covered only the sibling instance.

Root cause

examples/app-showcase/src/automation/flows/index.ts — InvoiceDualSignoffFlow. The notify_cleared node declares recipients: ['{record.account.owner}'] while the flow's start node declares no config.expand, so record.account is the raw scalar FK id and the relation hop resolves to nothing. The engine's own diagnostic already names both candidate fixes: add the relation to the start node's config.expand so the engine hydrates it, or address a scalar the trigger record already carries.

Reproduction

  1. Boot examples/app-showcase on framework a86db175.
  2. Take any flow:showcase_invoice_signoff request — seeded INV-1008, or raise a fresh one by PATCHing a draft invoice to status:'sent'.
  3. POST /api/v1/approvals/requests/…/approve as an entitled approver.

Observed: HTTP 500 RESUME_FAILED; sys_approval_request re-reads status:'approved' with the approve action row present; the flow run re-reads status:'failed'. Reproduced 2× on two separate invoices with a byte-identical error, plus the matching stranded-run ERROR in the boot log.

Source

Extracted from the QA run #7517 (framework a86db17, console 09987b68).

Activity

  1. huangyiirene commented on Aug 11, 2026

    @huangyiirene
    CollaboratorAuthor

    Closing as a duplicate of #7381 — already fixed on main before this card was filed; the QA run re-found it because its build predates the fix.

    Timeline, verified against GitHub rather than inferred:

    One nuance worth keeping from #7395's implementation notes: the "add expand: ['account'] and keep {record.account.owner}" shape this card's report implies does not work — showcase_account has no owner field (the injected owner column is owner_id). The merged fix re-points the recipient at {record.owner} and keeps the hydration for {record.account.name}.

    Residual for the next sweep, recorded on the run card rather than kept open here: re-run decision-only-via-service clause 2 on a build that includes #7395 to confirm the checklist item goes green.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions