koala73/worldmonitor · error
Read-back after PUT did not confirm expected filters.\n
Error message
Read-back after PUT did not confirm expected filters.\n${missingAfter.length ? ` missing generated: ${missingAfter.slice(0, 5).join(' | ')}\n` : ''}${missingProtected.length ? ` missing protected: ${missingProtected.join(' | ')}\n` : ''} What it means
After PUT, runApply reads back the project options and verifies that all expected generated patterns and all protected filters are present. If any are missing it throws with up to 5 missing generated lines and the full list of missing protected lines, indicating Sentry did not persist the filters exactly as sent.
Solutions
- Re-run the sync; transient overwrites often resolve on a second attempt.
- Check the read-back value size against Sentry's option length limits; shorten patterns if truncated.
- Check for concurrent writers to the project's filters:error_messages option and coordinate a maintenance window.
- Inspect the read-back value in Sentry UI to see exactly what persisted.
Example fix
// before // 500 patterns joined in one PUT value -> truncated by Sentry // after // batch the PUT or reduce generated patterns to essentials, then re-verify read-back
Defensive patterns
Strategy: retry
Validate before calling
const payload = patterns.join('\n');
if (payload.length > MAX_OPTION_LENGTH) throw new Error('Filter payload exceeds Sentry option size limit'); Try / catch
for (let attempt = 0; attempt < 3; attempt++) {
await putErrorMessageFilters(patterns, ...);
const readBack = await fetchProjectOptions(...);
if (patterns.every(p => readBack.has(p))) break;
await sleep(1000 * (attempt + 1));
} Prevention
- Keep total filter payload within Sentry option size limits to avoid truncation.
- Coordinate with anyone else who edits project options.
- Always read back after PUT and treat the read-back as the source of truth.
When it happens
Trigger: The read-back filters:error_messages set lacks one or more patterns just PUT: Sentry truncated or normalized the value (length limits, newline handling), a concurrent writer overwrote options, or the PUT actually failed silently (proxy/edge behavior).
Common situations: Filter text exceeding Sentry's option size limit causing truncation, another team member or automation saving project options concurrently, or a reverse proxy accepting the PUT but dropping the body.
Related errors
- PUT failed: HTTP ` : ''}
- Expected an array of Sentry issues. A Sentry error body is…
- GET failed: HTTP ` : ''}
- Read-back still contains legacy tutorial probe filters:\n
- Sentry issues pagination exceeded
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/0e0b47b30e1f59d9.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/sync-sentry-convex-probe-filters.mjs:453
}
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);
const readBackSet = new Set(readBackLines);
const missingAfter = patterns.filter((line) => !readBackSet.has(line));
const missingProtected = PROTECTED_ERROR_MESSAGE_FILTERS.filter(
(line) => !readBackSet.has(line),
);
if (missingAfter.length > 0 || missingProtected.length > 0) {
throw new Error(
'Read-back after PUT did not confirm expected filters.\n'
+ (missingAfter.length
? ` missing generated: ${missingAfter.slice(0, 5).join(' | ')}\n`
: '')
+ (missingProtected.length
? ` missing protected: ${missingProtected.join(' | ')}\n`
: ''),
);
}
const leftoverLegacy = LEGACY_TUTORIAL_PROBE_FILTERS.filter((line) =>
readBackSet.has(line),
);
if (leftoverLegacy.length > 0) {
throw new Error(
'Read-back still contains legacy tutorial probe filters:\n '
+ leftoverLegacy.join('\n '),
);View on GitHub (pinned to e586b8b4b8)