koala73/worldmonitor · error

Merge dropped protected filter

Error message

Merge dropped protected filter: ${line}

What it means

Before any PUT, runApply verifies that every entry in PROTECTED_ERROR_MESSAGE_FILTERS survived the merge of generated patterns with existing filters. If a protected (hand-maintained) filter would be dropped, the script aborts to prevent silently removing filters unrelated to the Convex probe lifecycle.

Solutions

  1. Re-add the missing protected filter in Sentry project options (filters:error_messages), then re-run the sync.
  2. Check recent Sentry UI/option changes that removed the protected filter.
  3. Inspect the merge computation if a code change could be misclassifying protected lines as stale.
  4. Use --dry-run to inspect the merged list before PUT.

Example fix

// before
// merge = generated + removed, protected line lost because remote options were edited in UI
// after
const merged = dedupe([...remote, ...PROTECTED_ERROR_MESSAGE_FILTERS, ...appended].filter(l => !removedSet.has(l)));
Defensive patterns

Strategy: validation

Validate before calling

const mergedSet = new Set(merged);
const dropped = PROTECTED_ERROR_MESSAGE_FILTERS.filter(l => !mergedSet.has(l));
if (dropped.length) throw new Error('Merge would drop: ' + dropped.join(', '));

Prevention

When it happens

Trigger: The merge logic computed a merged list that omits a protected filter — e.g. existing project options no longer contain it, so preservedOther is missing it, or the merge/replace branch incorrectly excludes it.

Common situations: Someone deleted a protected filter manually in the Sentry UI, so the remote options no longer include it and the merge can't re-include it; or a code change altered merge semantics so protected lines are treated as legacy/removable.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22). Data as JSON: /api/errors/2db470def1627369. Report an issue: GitHub.

Appendix: source

Thrown at scripts/sync-sentry-convex-probe-filters.mjs:427

      ? options['filters:error_messages']
      : '';
  const currentLines = splitErrorMessageFilters(currentText);
  const { merged, appended, removed, preservedOther } = mergeErrorMessageFilters(
    currentLines,
    patterns,
  );
  const mergedText = joinErrorMessageFilters(merged);

  console.log(`Sentry project ${org}/${project}`);
  console.log(`  current lines: ${currentLines.length}`);
  console.log(`  generated internal patterns: ${patterns.length}`);
  console.log(`  to append: ${appended.length}`);
  console.log(`  to remove (legacy/stale Convex probe): ${removed.length}`);
  console.log(`  preserved other: ${preservedOther.length}`);

  for (const line of PROTECTED_ERROR_MESSAGE_FILTERS) {
    if (!merged.includes(line)) {
      throw new Error(`Merge dropped protected filter: ${line}`);
    }
  }

  if (opts.dryRun) {
    console.log('--dry-run: skipping PUT. Merged filters:\n');
    console.log(mergedText);
    return;
  }

  await putErrorMessageFilters(token, org, project, mergedText);

  const after = await fetchProjectOptions(token, org, project);
  const afterOptions = /** @type {Record<string, unknown>} */ (after.options ?? {});
  const readBack =
    typeof afterOptions['filters:error_messages'] === 'string'
      ? afterOptions['filters:error_messages']
      : '';
  const readBackLines = splitErrorMessageFilters(readBack);

View on GitHub (pinned to e586b8b4b8)