How a Silent Parser Bug Deleted 31 Blog Posts from Production
Discovery: "Wait, Why Are There So Few Posts?"
Last weekend, I was doing a routine check after publishing a new technical article when something caught my eye: our homepage blog list showed only 12 posts. But my local development environment had 43.
My first thought was caching. I hard-refreshed the browser, even opened an incognito window. No change. When I SSH'd into the production server and opened posts.js, my stomach dropped: the file contained exactly 12 posts. We'd lost 31 articles.
Diagnosis: A Parser That Silently Ate Our Data
I immediately checked the Git log. The last commit showed our automated publishing script (publish.js) had added a new post. But the diff was horrifying: the entire file had been rewritten, and all the old content was gone.
When I examined the script, I found the culprit. Here's how we were reading existing posts:
// WRONG APPROACH
let existingPosts = [];
try {
const fileContent = fs.readFileSync('posts.js', 'utf8');
const jsonMatch = fileContent.match(/export const posts = (\[[\s\S]*\]);/);
if (jsonMatch) {
existingPosts = JSON.parse(jsonMatch[1]);
}
} catch (e) {
// Silently continue
console.log('Could not read existing posts, creating new list');
}
Here's what happened: in a previous publish, a small syntax error had crept into posts.js (an extra comma). When JSON.parse() hit that error, it threw an exception. But our catch block just logged a message and continued with an empty array. The script then overwrote 31 posts with a file containing only the new article.
Why Didn't We Notice?
- Silent failure: The script completed successfully, returned exit code 0
- Local-production drift: Our local environment still had the old file; only production was affected
- Gradual loss: It didn't happen all at once—posts disappeared over several publish cycles
Recovery Operation
Fortunately, we had regular backups. Here's what we did:
1. Restore from Backup
# Find the last healthy backup
ls -lt backups/posts.js.* | head -5
# The backup from 3 days ago looked complete
cp backups/posts.js.2024-01-15 posts.js.recovered
# Extract the missing posts
node extract-missing.js
2. Write a New, Safe Parser
To prevent this from ever happening again, we completely rewrote the parser:
// CORRECT APPROACH
function loadExistingPosts(filePath) {
if (!fs.existsSync(filePath)) {
throw new Error(`FATAL: ${filePath} not found. Halting publish.`);
}
const fileContent = fs.readFileSync(filePath, 'utf8');
const jsonMatch = fileContent.match(/export const posts = (\[[\s\S]*\]);/);
if (!jsonMatch) {
throw new Error('FATAL: Invalid posts.js format. Manual intervention required.');
}
let posts;
try {
posts = JSON.parse(jsonMatch[1]);
} catch (e) {
// Detailed error message + file backup
const backupPath = `${filePath}.error-${Date.now()}`;
fs.copyFileSync(filePath, backupPath);
throw new Error(
`FATAL: JSON parse error. File backed up to: ${backupPath}\n` +
`Error: ${e.message}\n` +
`Content preview: ${jsonMatch[1].substring(0, 200)}...`
);
}
if (!Array.isArray(posts) || posts.length === 0) {
throw new Error(`FATAL: Unexpected data structure. Found ${posts.length} posts.`);
}
console.log(`✓ Successfully loaded ${posts.length} existing posts`);
return posts;
}
3. Additional Safety Layers
- Pre-commit hook: Checks post count before each publish; halts if there's a >20% drop
- Automatic backups: Creates timestamped backup before every change
- Dry-run mode: Preview changes with
--dry-runflag - Slack notifications: Reports post count after each successful publish
The Bigger Lesson: Fail Fast
This incident reminded us of a critical software principle: silently swallowing errors is far more dangerous than the errors themselves.
This is especially critical in content management systems because:
- Data loss is often irreversible
- Multiple operations can stack up before the problem is noticed
- SEO impact isn't immediate—it degrades gradually
Check Your Own Site
If you're running automated content publishing systems, we recommend these checks:
- Review all
try-catchblocks—do you really need to swallow that error? - Add assertions to critical data operations (post count, file size, etc.)
- Log before/after comparisons for all changes
- Ensure you have a regular backup strategy
AICompatible.com's site crawler detects these kinds of structural issues: sitemap inconsistencies, missing pages, broken JSON-LD structures. It could have caught a data loss like ours before we noticed. But most importantly: if you have "silent error swallowing" anywhere in your code, fix it now. When something goes wrong, the thing that will save you isn't hiding the error—it's making it scream.