Bug: eventFilterMatches returns false for nested $exists: false when the parent key is missing or null
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 78/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- node.js, typescript
調査の方向性
まず packages/core/src/eventFilterMatches.ts と packages/core/test/eventFilterMatches.test.ts の既存ケースを確認します。issue にあるネストされた $exists: false のケースを、親キーが存在しない場合と null の場合も含めて再現し、その後、トップレベルのケースが引き続き通ることを確認します。報告された4つの結果がすべて true を返し、既存のテストが通れば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
eventFilterMatches returns false for a nested $exists: false filter when the parent key is missing or null in the payload. The function returns false for any non-empty filter as soon as it meets an undefined/null payload, before it evaluates $exists. This is user-facing through retry.fetch's bodyFilter, which calls eventFilterMatches on the response body.
Reproduction
- Setup:
packages/coreonmain. - Command:
npx tsx repro.tsfrompackages/corewith:
import { eventFilterMatches } from "./src/eventFilterMatches.js";
const f = { user: { email: [{ $exists: false }] } };
console.log(eventFilterMatches({}, f)); // false
console.log(eventFilterMatches({ user: null }, f)); // false
console.log(eventFilterMatches({ user: {} }, f)); // true
console.log(eventFilterMatches({}, { email: [{ $exists: false }] })); // true
- Trigger: a nested filter whose leaf is
$exists: false, used with a payload where an ancestor key is absent ornull.
Actual behavior
{} {"user":{"email":[{"$exists":false}]}} => false
{"user":null} {"user":{"email":[{"$exists":false}]}} => false
{"user":{}} {"user":{"email":[{"$exists":false}]}} => true
{} {"email":[{"$exists":false}]} => true
Expected behavior
All four should return true. If user is missing, then user.email doesn't exist either, which is exactly what $exists: false asserts. Top-level $exists: false already behaves that way (case 4, and the existing test "should return true when payload does NOT have a key that $exists = false"). Nesting the same condition one level deeper shouldn't flip the result.
Environment
- Version/commit:
main@ 93465d8549a735074d1ce7696bae3faebe577e8d - OS: Ubuntu (Linux), Node v24.21.0
- Relevant configuration: none; pure function. Reachable from
retry.fetch(url, { retry: { byStatus: { "...": { strategy: "backoff", bodyFilter } } } })
Evidence
- Early return for
undefined/nullpayload with a non-empty filter: https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/core/src/eventFilterMatches.ts#L7-L14 - Recursion into nested object filters: https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/core/src/eventFilterMatches.ts#L61-L71
retry.fetchbodyFilterpath: https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/trigger-sdk/src/v3/retry.ts#L449-L460bodyFilter: EventFilterin the fetch retry schema: https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/core/src/v3/schemas/fetch.ts#L17 and https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/core/src/v3/schemas/fetch.ts#L39- Existing tests cover only top-level
$exists: https://github.com/triggerdotdev/trigger.dev/blob/93465d8549a735074d1ce7696bae3faebe577e8d/packages/core/test/eventFilterMatches.test.ts#L193-L208
Additional context
Confirmed: the four results above, from running the source on main.
Inference: for retry.fetch, a bodyFilter such as { error: { retryAfter: [{ $exists: false }] } } won't match a body that has no error object at all. That strategy is then skipped. I haven't exercised this through retry.fetch end to end.
Possible fix: when the payload is undefined/null, evaluate the filter against an empty object (or recurse with {}) instead of returning false, so that $exists: false and $isNull-style leaves still get evaluated.
Found with an anti-slop oxlint scan (no-runtime-typeof), then checked by hand.
- 主要言語
- TypeScript
- スター
- 16.5k
- フォーク
- 1.5k
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 17
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
triggerdotdev/trigger.dev のほかの issue
-
bug: retry.fetch ignores the caller's abort signal and retries aborted requests再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
triggerdotdev/trigger.dev#5116 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
bug: Chat transport crashes on Safari < 17.4: AbortSignal.any is not a function再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 83/100
triggerdotdev/trigger.dev#5098 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
bug: Side menu items lose their active state on detail pages再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
triggerdotdev/trigger.dev#5088 ·
メンテナーはふだん 1 日以内に返信
-
bug: RBAC loader logs "plugin found but failed to load" when @triggerdotdev/plugins is simply not installed再び着手できるかも @itsfaryal が 17 日前に担当しましたが、オープン中のプルリクエストはありません。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
triggerdotdev/trigger.dev#5083 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 83/100
triggerdotdev/trigger.dev#5072 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
triggerdotdev/trigger.dev の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
bug platform-android
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
Termix-SSH/Mobile#146 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
devswha/herdr-web-ui#3875 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
-
area: runtime chore cli consistency dependencies developer-experience difficulty: easy discovery documentation enhancement good first issue help wanted hygiene json-output packaging priority: P3 tests version
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信