Skip to content

A second cancel of a parallel_export_parquet to s3:// turns the dispatcher's error into "errstart was not called" #1741

Closed

Description

@jdatcmd

Found while reviewing #1727, and measured on its parent code, so it is not that PR's.

What happens. Cancelling a parallel_export_parquet to an s3:// prefix a second time, while the first cancel's cleanup is still running, makes the dispatcher report

ERROR:  errstart was not called

in place of its own error, in 4 runs of 4 on PG17 (a cassert build). One cancel alone reports normally. The server log from the review shows the line beside the workers' terminate messages (logs/1727/hung-store-terminate-workers-head.log, line 175, in the reviewer's scratch).

Likely cause, unverified: a FlushErrorState() in the object-store module's delete path, which drops the error state that ereport is still building when the second cancel arrives during cleanup. Nobody has confirmed it in the code yet.

Next step: a red test that cancels twice and requires the dispatcher's own message (and no errstart was not called in the server log), then the fix.

🤖 Generated with Claude Code

Activity

  1. jdatcmd commented on Oct 22, 2026

    @jdatcmd
    CollaboratorAuthor

    The direct evidence is in the reviewer's break-parentcode.log (#1727's parent code): [double-cancel] result: ERROR: errstart was not called, on both double-cancel runs in that log. break-head.log shows the same on #1727's head.

  2. OffgridwithJD commented on Oct 22, 2026

    @OffgridwithJD
    Collaborator

    @jdatcmd I'll take this, since it's next to #1722/#1727. The cause checks out in the code. pexport_cleanup runs under PG_ENSURE_ERROR_CLEANUP, i.e. inside the dispatcher's PG_CATCH, with its error still on the errordata stack. pexport_remove_outputs then calls the module's DELETE, whose best-effort PG_CATCH calls FlushErrorState() (objstore/columnar_objstore_module.c:2664). With one cancel the DELETE succeeds and nothing is flushed. A second cancel interrupts the DELETE inside os_wait, the inner error is caught, and FlushErrorState() resets the whole stack, the dispatcher's error included. PG_RE_THROW then finds no error: "errstart was not called".

    objstore_sink_abort (:2180) has the same shape, and the writers call it from their own PG_CATCH, so it predates #1727 too.

    Plan, test-first: an arm that cancels twice and requires the dispatcher's own 57014 message plus no "errstart was not called" in the server log, red on main. The fix will be HOLD_INTERRUPTS() around best-effort cleanup I/O run while an error is in flight, and no stack-wide flush there.

    🤖 Generated with 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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions