-
-
Notifications
You must be signed in to change notification settings - Fork 953
Description
Provide environment information
System:
OS: macOS 15.7.3
CPU: (16) arm64 Apple M4 Max
Memory: 1.99 GB / 64.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.16.0 -
Yarn: 1.22.22
npm: 10.9.2
pnpm: 10.26.2
Watchman: 2026.01.05.00
Describe the bug
The getRunIdForOptions function is duplicated in two locations with inconsistent fallback behavior. The SDK version (packages/trigger-sdk/src/v3/streams.ts) lacks fallback logic that exists in the core implementation (packages/core/src/v3/realtimeStreams/manager.ts).
When calling streams.pipe("key", stream, { target: "root" }) from a root task (a task not triggered by another task), the SDK throws an error instead of falling back to the current run ID. The semantic meaning of target: "root" is "send to the root of this task tree" - if the current task IS the root, it should behave the same as target: "self".
Reproduction repo
This can be reproduced in any Trigger.dev project using the SDK's streams.pipe() API with target: "root" from a directly-triggered task.
To reproduce
import { streams, task } from "@trigger.dev/sdk";
// This task is triggered directly (not a child of another task)
export const rootTask = task({
id: "root-task",
run: async (payload) => {
const myStream = createSomeAsyncGenerator();
// This will throw an error even though it should work
const { waitUntilComplete } = streams.pipe("output", myStream, {
target: "root" // Fails because rootTaskRunId is undefined for root tasks
});
await waitUntilComplete();
},
});Steps:
- Create a task that is triggered directly (not as a child of another task)
- Call streams.pipe() with { target: "root" }
- Observe the error is thrown
Additional information
Root Cause: Two getRunIdForOptions functions exist with different behavior:
| File | Fallback for "root"/"parent"? |
|---|---|
packages/trigger-sdk/src/v3/streams.ts:665-683 |
❌ No |
packages/core/src/v3/realtimeStreams/manager.ts:141-159 |
✅ Yes |
Why the core fallback is unreachable: The SDK resolves targets to string IDs FIRST, then passes them to the core. By the time StandardRealtimeStreamsManager.pipe() is called, it receives a string ID (or an error was already thrown), so its fallback logic is dead code for SDK callers.
Evidence the fallback is intended:
- Documentation (
docs/tasks/streams.mdx:374,399) showstarget: "root"as valid usage - Internal API (
packages/core/src/v3/runMetadata/manager.ts:330-333) passes semantic targets directly and relies on the fallback
Origin: Both functions introduced in same commit (536d9fa21 - "feat(realtime): Realtime streams v2 #2632"). Inconsistency was present from creation.
Affected functions: streams.pipe(), streams.append(), streams.writer() - all use the same getRunIdForOptions in streams.ts