The 50MB Markdown Files That Broke Our Server: A Debugging Tale

Article illustration 1

In the world of software development, few challenges are as frustrating as intermittent performance issues that defy explanation. When server response times began fluctuating wildly—sometimes completing in 50ms, other times taking up to 1000ms—one development team found themselves on a month-long quest to identify the root cause. What they discovered serves as a valuable lesson about the unexpected ways user-generated content can impact system performance.

The Chase: A Month of Dead Ends

About a month ago, the team noticed their server response times becoming increasingly erratic. The initial investigation focused on the usual suspects: recent code changes, dependency updates, and traffic spikes. But none of these factors correlated with the performance degradation.

"We tried correlating the issue with a number of factors," explained the developer behind the debugging effort, "including recent changes to the codebase, recent dependency updates, spikes in traffic. But nothing explained the issue."

The team turned to production profiling to understand where the application was spending its time. Flamegraphs revealed some interesting patterns, though nothing immediately alarming. The team was surprised by how much time React spent rendering the UI, but attributed this to the scale of their operation—serving thousands of requests across thousands of MCP server repositories.

Undeterred, the team took a meticulous approach, examining every function that stood out in the flamegraphs. They wrote benchmarks for each suspicious function and optimized them one by one. Yet, days passed, and the mysterious performance fluctuations continued.

The Trap: When Instrumentation Revealed the Pattern

The breakthrough came not from sophisticated monitoring tools, but from a simple, targeted instrumentation approach. The team decided to instrument the renderToPipeableStream function to log rendering times that exceeded the 100ms threshold.

This simple change quickly revealed a pattern: some URLs were taking significantly longer to render than others. The irregular performance wasn't random—it was directly tied to specific content being processed.

The Culprit: Oversized Markdown Files

The investigation ultimately led to a surprising culprit: the team had accidentally indexed very large markdown files—some exceeding 50MB—in their database.

"Not surprisingly, parsing 50MB+ markdown files and then converting them to React elements took a lot of time," the developer noted.

What made this issue particularly difficult to diagnose was the team's own optimization efforts. They had written a custom markdown parser specifically designed to handle large files without blocking the main thread. While this approach prevented the application from freezing, it masked the performance impact in flamegraphs, which simply showed "a lot of work across thousands of requests."

Reflection on Instrumentation

The debugging process revealed important limitations in the team's existing monitoring approach. Their extensive instrumentation focused on function and span-level metrics rather than route-level insights.

"While some tools did provide route level insights (Sentry), the pattern wasn't obvious in aggregate," the developer explained. "The issue would become visible across all routes once we start processing one of these large files."

Interestingly, a simple logging technique proved more effective than sophisticated monitoring tools. By logging the first route processed before CPU spikes occurred, the team could trace the performance issues back to their source.

The same approach later revealed related issues with processing and serving user-generated content, including attempts to server-side syntax highlight very large files or serve binary files as text in edge cases.

The Lesson: Never Trust User Content

The most significant takeaway from this experience was a fundamental principle of web development: never trust user content.

"We are aggregating data across thousands of MCP server repositories. I should have known better," the developer admitted.

In response to this incident, the team implemented checks to ensure that content being downloaded or displayed falls within expected parameters. This proactive approach prevents similar performance issues in the future.

This debugging story serves as a reminder that even with extensive instrumentation and monitoring, the root cause of performance issues can remain elusive. Sometimes, the simplest diagnostic approaches—targeted logging and careful content validation—reveal problems that sophisticated tools might miss. As applications grow more complex and handle increasing volumes of user-generated content, the lessons from this 50MB markdown file incident become ever more relevant.