Skip to content

A schedule-triggered flow's notify delivers nothing on a multi-organization install: the run carries no organization, so the tenant-scoped inbox/delivery writes are refused (#8844) while the run reads healthy #16659

Description

@os-sam

Measured on @objectstack/cli 17.3.0 (objectstack dev --fresh, memory AND sqlite drivers), in an app that seeds 12 employer organizations plus the platform one (objectstack-ai/ats, card F5/F6 — objectstack-ai/ats#7).

What happens

A type: 'schedule' flow (runAs: 'system', start node config.schedule: { type: 'cron', expression: '* * * * *' }) whose loop body ends in a notify node (channels: ['inbox'], recipients = user ids) runs on every tick, selects the right rows, and its update_record steps land. The notifications do not:

So on any install with more than one sys_organization, a scheduled flow that notifies is a green run that delivers nothing, and its history never persists. Record-change flows are unaffected (the triggering session's organization is threaded, and delivery works on both drivers).

Why the app cannot route around it

  • NotifyConfigSchema is strictObject and has no organization key, so a flow cannot hand notify the record's organization_id (an interview row carries one; a platform-global object such as a candidate credential — tenancy: { enabled: false } — carries none at all).
  • The run context is built by the trigger; a runAs: 'system' flow has no session to borrow from.
  • A defineJob handler receives { jobId, data, bundle, ql, logger } — no messaging handle — so moving the work to a job does not reach the inbox either.

Reproduction

  1. Any stack with requires: ['automation', 'triggers', 'approvals', 'messaging'] and ≥ 2 organizations in sys_organization.
  2. A schedule flow: get_recordloopnotify (inbox, user-id recipients). Cron * * * * * for the test.
  3. Wait one tick; read GET /api/v1/notifications as a recipient (empty), and the boot log (no organization in scope + the REFUSED line for sys_automation_run).
  4. Trigger the same flow via POST /api/v1/automation/<name>/trigger under a session: the recipient now sees the row.

Options seen from the app side (not a recommendation)

  • Let a scheduled trigger carry an acting organization (a start-node key, or a per-organization fan-out of the sweep).
  • Let notify accept an organization from the record (organizationId: '{record.organization_id}').
  • Declare the user-keyed inbox objects (sys_inbox_message, sys_notification_delivery, sys_notification_receipt) platform-global, since an inbox row belongs to a user, not to an organization — the refusal message itself suggests this route for rows that "belong to no organization".

Related, closed: #11303 (threaded the run's organization into notify — this is the trigger family that has none to thread), #14501, #10673.

Activity

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions