{"record":{"id":"2db470def1627369","repo":"koala73/worldmonitor","slug":"merge-dropped-protected-filter-line","errorCode":null,"errorMessage":"Merge dropped protected filter: ${line}","messagePattern":"Merge dropped protected filter: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/sync-sentry-convex-probe-filters.mjs","lineNumber":427,"sourceCode":"      ? options['filters:error_messages']\n      : '';\n  const currentLines = splitErrorMessageFilters(currentText);\n  const { merged, appended, removed, preservedOther } = mergeErrorMessageFilters(\n    currentLines,\n    patterns,\n  );\n  const mergedText = joinErrorMessageFilters(merged);\n\n  console.log(`Sentry project ${org}/${project}`);\n  console.log(`  current lines: ${currentLines.length}`);\n  console.log(`  generated internal patterns: ${patterns.length}`);\n  console.log(`  to append: ${appended.length}`);\n  console.log(`  to remove (legacy/stale Convex probe): ${removed.length}`);\n  console.log(`  preserved other: ${preservedOther.length}`);\n\n  for (const line of PROTECTED_ERROR_MESSAGE_FILTERS) {\n    if (!merged.includes(line)) {\n      throw new Error(`Merge dropped protected filter: ${line}`);\n    }\n  }\n\n  if (opts.dryRun) {\n    console.log('--dry-run: skipping PUT. Merged filters:\\n');\n    console.log(mergedText);\n    return;\n  }\n\n  await putErrorMessageFilters(token, org, project, mergedText);\n\n  const after = await fetchProjectOptions(token, org, project);\n  const afterOptions = /** @type {Record<string, unknown>} */ (after.options ?? {});\n  const readBack =\n    typeof afterOptions['filters:error_messages'] === 'string'\n      ? afterOptions['filters:error_messages']\n      : '';\n  const readBackLines = splitErrorMessageFilters(readBack);","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/scripts/sync-sentry-convex-probe-filters.mjs#L409-L445","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-add the missing protected filter in Sentry project options (filters:error_messages), then re-run the sync.","Check recent Sentry UI/option changes that removed the protected filter.","Inspect the merge computation if a code change could be misclassifying protected lines as stale.","Use --dry-run to inspect the merged list before PUT."],"exampleFix":"// before\n// merge = generated + removed, protected line lost because remote options were edited in UI\n// after\nconst merged = dedupe([...remote, ...PROTECTED_ERROR_MESSAGE_FILTERS, ...appended].filter(l => !removedSet.has(l)));","handlingStrategy":"validation","validationCode":"const mergedSet = new Set(merged);\nconst dropped = PROTECTED_ERROR_MESSAGE_FILTERS.filter(l => !mergedSet.has(l));\nif (dropped.length) throw new Error('Merge would drop: ' + dropped.join(', '));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include protected filters explicitly in the merge output, not just preserve-if-present.","Check Sentry UI before running: protected filters must exist remotely.","Preview merges with --dry-run."],"tags":["invariant","sentry","config"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-22T01:50:49.965Z","contentChangedAt":"2026-09-22T01:50:49.965Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}