Skip to content

Release v2.0.3#21

Open
msimerson wants to merge 4 commits intomasterfrom
release-2.0.3
Open

Release v2.0.3#21
msimerson wants to merge 4 commits intomasterfrom
release-2.0.3

Conversation

@msimerson
Copy link
Copy Markdown
Member

@msimerson msimerson commented Apr 24, 2026

  • register transformer.once('end'...) before piping

maybe fixes haraka/Haraka#3551

- doc(CONTRIBUTORS): updated
- doc(CHANGELOG): add commit messages for 2.0.3
@msimerson
Copy link
Copy Markdown
Member Author

Root cause: Introduced in haraka-message-stream v2.0.0 (shipped with Haraka 3.1.4). The pipe() method added an #inPipe guard but registered the cleanup listener (#inPipe = false) after calling source.pipe(transformer).pipe(destination). Node.js's pipe registers its own 'end' listener on transformer at that point. Since EventEmitter fires listeners in registration order, when transformer emits 'end':

  1. Pipe's listener fires first → calls destination.end() → DKIMSignStream invokes its callback synchronously → next() fires → process_delivery tries to call message_stream.pipe() again → throws "Cannot pipe while currently piping" (because #inPipe is still true)
  2. Message-stream's listener fires second → #inPipe = false (too late)

Fix (message-stream/index.js): Move the transformer.once('end', ...) and transformer.once('error', ...) registrations to before the source.pipe(transformer).pipe(destination) call. This ensures the #inPipe = false cleanup fires first, making sequential pipes triggered synchronously from a pipe's end callback safe.

The DKIM plugin's hook_pre_send_trans_email (registered on queue_outbound) pipes the message stream to compute a DKIM signature; when complete it calls next() synchronously. This leads queue_outbound_respond → send_trans_email → process_delivery → a second message_stream.pipe() before the guard was cleared.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Releases v2.0.3 with a fix to MessageStream.pipe() that prevents #inPipe from blocking a second, synchronous pipe() started from a previous pipe’s end flow (regression related to haraka/Haraka#3551).

Changes:

  • Fix: register transformer.once('end' ...) (and error) handlers before calling .pipe() so #inPipe is cleared before the destination’s end path can synchronously trigger another pipe().
  • Test: add a regression test covering “sequential pipe” initiated synchronously from the first destination’s final().
  • Release/ops: bump version to 2.0.3, add changelog link entry, adjust CI prettier job conditions, and update generated contributor metadata.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
index.js Moves end/error handler registration before piping to avoid synchronous re-entrancy hitting #inPipe.
test/message-stream.js Adds a regression test that reproduces the synchronous sequential pipe() scenario.
package.json Bumps package version to 2.0.3.
CHANGELOG.md Adds 2.0.3 header and release link (currently missing details).
CONTRIBUTORS.md Updates generated contributor commit counts.
.github/workflows/ci.yml Prevents prettier workflow from running on fork PRs and adjusts branch selection logic.
.github/FUNDING.yml Removes GitHub Sponsors configuration entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CHANGELOG.md
@msimerson msimerson marked this pull request as ready for review April 24, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Haraka 3.1.4+ "[CRIT] [-] [core] Error: Cannot pipe while currently piping" with dkim plugin with signing disabled

2 participants