One Lab's Unversioned Library Dependency Broke 14 of 20 Reanalysis Scripts
On a Friday afternoon in early 2025, a graduate student in a mid-sized computational biology lab sat down to re-run a set of analysis scripts that had produced figures for a paper published two years earlier. The task was routine: update a few file paths, hit run, and confirm that the results still held. Instead, the terminal filled with red error messages. Fourteen of the twenty scripts crashed within seconds. The culprit turned out to be a single unversioned library dependency — a package that had been updated silently since the original analysis, breaking the code that relied on its old behavior.
The Script That Wouldn't Run
The student had pulled the scripts from the lab's internal repository, where they had been stored alongside the raw data after the paper's publication. The data files were intact, but the code was brittle. The error messages pointed to a function from a widely used data-wrangling library. The function's signature had changed in a minor release — a new argument was required, and the old syntax was deprecated.
Digging deeper, the student found that the original analysis had been performed using a version of the library that was current at the time, but no record existed of which version that was. The lab's practice was to install packages with a simple pip install or install.packages() command, without pinning version numbers. Over the intervening months, the library had been updated twice. The scripts assumed the old behavior, and the new release broke them.
This pattern is not unusual. In a 2023 survey of researchers in ecology and evolutionary biology, nearly half reported that they could not reproduce their own analyses from two years prior. The reasons often boiled down to software dependencies that had shifted. The graduate student's experience was a miniature version of a problem that has plagued computational science for at least a decade.
The lab's principal investigator was initially skeptical. The PI had assumed that storing the scripts alongside the data was sufficient for reproducibility. But the failing scripts told a different story: the code was only half the equation. The environment in which it ran mattered just as much, and that environment had not been preserved.
How Code Decays Over Time
Software environments are inherently fragile. A modern data analysis pipeline might depend on dozens of libraries, each with its own dependencies. Package managers like pip, conda, or CRAN make it easy to install these libraries, but they do not, by default, enforce version consistency across time. When a library is updated — to fix a bug, add a feature, or patch a security vulnerability — the old version is often overwritten or becomes unavailable.
Consider the case of the R package tidyverse, a collection of data science tools that is among the most popular in the R ecosystem. Between 2017 and 2023, the tidyverse underwent several breaking changes. Functions such as spread() and gather() were deprecated in favor of pivot_wider() and pivot_longer(). Code written in 2017 that used the old functions would fail if run with the current version of the package, unless the user explicitly installed an older version.
This phenomenon — sometimes called "software decay" — is not limited to R. Python's scientific stack, including NumPy and pandas, has seen similar transitions. NumPy 2.0, released in 2024, removed many deprecated functions and changed default behaviors, breaking a substantial fraction of existing code. The Python community has responded with tools like pip freeze and lock files, but these practices are not universally adopted in academic labs.
When a researcher tries to re-run an old analysis, they are essentially performing a form of computational archaeology. They must reconstruct the original software environment from clues: the date of the analysis, the version of the operating system, the state of the package repositories at that time. Without a snapshot of the environment, this reconstruction is often incomplete or impossible.
The decay is not just about version mismatches. Even when the same version of a library is available, the underlying system libraries — such as those for linear algebra or image processing — may have changed. A script that compiled and ran on Ubuntu 20.04 might fail on Ubuntu 22.04 due to differences in the system's C library or the default compiler flags. For example, the GNU Scientific Library (GSL) changed its random number generator defaults in version 2.0, causing simulations that relied on the old generator to produce different results. Such subtle shifts can be nearly impossible to detect without a preserved environment.
The Lab's Workflow Exposed
When the graduate student reported the failures, the lab's postdocs and PI gathered to understand what had gone wrong. The original analysis had been conducted by a postdoc who had since moved to a different institution. The postdoc had left behind the scripts and a README file, but no lockfile or environment specification. The README listed the required libraries but not their versions.
The lab had adopted some good practices: they used version control (Git) for the code, and they archived the raw data in a public repository with a DOI. But they had not archived the compute stack — the specific combination of operating system, library versions, and compiler settings that made the code run. This is a common oversight in academic code. A 2022 analysis of 2,000 computational papers found that fewer than 10% provided any information about the software environment beyond a list of package names.
The lab's workflow was typical of many groups in the life sciences. Researchers wrote scripts interactively, often on their own laptops, and then copied them to a shared drive. When a paper was submitted, the code was sometimes deposited in a repository, but the environment was assumed to be reproducible by anyone with the same operating system and package manager. That assumption proved false.
The failure was not total. Six of the twenty scripts ran without errors. These scripts used only base R or Python standard library functions, which had not changed. But the fourteen that failed relied on external packages — the very tools that make modern data analysis efficient and powerful. The lab had inadvertently built a house of cards.
Concrete Costs of Broken Scripts
The immediate cost was time. The graduate student spent two weeks attempting to rebuild the software environment, installing different versions of the broken library and its dependencies until the scripts ran again. In some cases, the exact version of a dependency was no longer available from the official package repository, and the student had to download it from an archived source or build it from source code.
Not all results could be recovered. For three of the scripts, the output figures differed slightly from the originals, even after the environment was reconstructed. The differences were small — a few percentage points in some summary statistics — but they raised questions about which numbers were correct. The lab eventually decided to correct one published figure in an erratum, after verifying that the qualitative conclusions remained unchanged.
The estimated total lost productivity across the lab was roughly 50 hours. This included the grad student's debugging time, the postdocs' consultation time, and the PI's review of the corrected figures. For a small lab with limited funding, 50 hours represented a significant fraction of a person-month of research effort.
Beyond the immediate hours, there was an erosion of trust in the earlier work. The PI began to wonder whether other unpublished analyses, done with similar workflows, might also be unreproducible. The lab's internal culture shifted: new projects now include a requirement for environment documentation, but the older projects remain a source of unease.
The incident also delayed a collaboration with another group that wanted to build on the original results. The collaborators could not run the scripts on their own systems, and the back-and-forth to resolve the dependency issues added weeks to the project timeline.
These costs are not unique to this lab. In a 2021 survey of researchers in computational biology, roughly 30% reported that they had abandoned a reanalysis effort due to software dependency issues. Another 20% said they had published results that they later could not reproduce themselves. The cumulative effect on scientific progress is difficult to quantify, but it is almost certainly substantial — wasted hours, delayed discoveries, and uncorrected errors that propagate through the literature.
Tools That Could Have Prevented This
The good news is that several well-established tools exist to prevent exactly this kind of failure. The simplest is version pinning: using a lockfile that records the exact version of every dependency. In Python, pip freeze generates a list of installed packages with version numbers, which can be saved as requirements.txt. In R, the renv package creates a project-specific library with a lockfile. Conda, a cross-language package manager, can export the full environment specification as a YAML file.
For full reproducibility, containerization tools like Docker or Singularity go a step further. They package the entire operating system, libraries, and code into a single image that can be run on any machine. A Docker image is a snapshot of the compute environment at a moment in time. If the lab had created a Docker image for the original analysis, the graduate student could have pulled it and run the scripts without any dependency issues.
Continuous integration (CI) testing, commonly used in software development, can also be applied to scientific code. A CI service can run the analysis scripts on a fresh environment every time the code is updated, catching dependency breaks before they cause problems. Some journals now recommend or require authors to use CI as part of their submission process. For instance, the Journal of Open Source Software (JOSS) runs automated tests on submitted code, and the American Journal of Political Science recently piloted a reproducibility check that includes environment validation.
Tools like Codecheck and ReproZip provide an audit trail for computational analyses. Codecheck allows reviewers to verify that the code produces the claimed results by running it in a controlled environment. ReproZip captures all the files and dependencies needed to reproduce an analysis, creating a portable bundle. These tools are not yet widespread, but they are gaining traction in fields like computational neuroscience and bioinformatics.
Even a simple README file with a list of dependencies and version numbers, along with instructions for setting up the environment, would have saved the lab significant time. The key is to treat the software environment as part of the research output, not as an afterthought.
However, these tools are not without trade-offs. Version pinning can lead to "dependency hell" when trying to install packages with conflicting requirements. Container images can be large (often several gigabytes) and require storage and bandwidth. CI testing adds overhead to the development process. Some researchers worry that the burden of reproducibility is falling on individual labs, rather than on the infrastructure providers. A counter-argument is that investing in these tools upfront saves time later, but the upfront costs can be significant for a small lab with limited computational expertise.
A Minimal Standard for Computational Work
What would a minimal standard for computational reproducibility look like? Several groups have proposed checklists. The metadata mandate from one funding agency fixed a similar proportion of reanalysis pipelines by requiring that all data be accompanied by machine-readable metadata. A comparable approach for code would require that every analysis script be accompanied by a machine-readable environment specification.
At a minimum, researchers should version-lock every dependency. This means using a lockfile or environment file that can be used to recreate the exact software stack. The lockfile should be stored alongside the code and data, ideally in the same repository. Second, the entire compute environment should be archived, either as a container image or as a virtual machine snapshot. Third, scripts should be run fresh in a clean environment before submission, to confirm that they work outside the original machine.
Open-source tools with long support are preferable to proprietary ones, because they are more likely to remain available and maintainable. The lab adopted conda environments with pinned versions after the incident, and they now use Docker for all new projects. But there is a tension: these tools add overhead. Setting up a Docker image requires learning a new skill, and maintaining it adds to the workload. Some researchers argue that the burden should be on journals and funders to provide infrastructure, not on individual labs.
Reasonable people disagree on how much reproducibility is enough. A checklist approach can become bureaucratic, and not every analysis needs to be reproducible down to the operating system kernel. But the incident in this lab shows that even a modest investment in environment preservation can prevent a cascade of failures. The cost of doing so upfront is far lower than the cost of reconstructing an environment years later — or, worse, publishing results that cannot be verified.
The broader lesson is that computational science is still maturing in its handling of software. Unlike wet-lab protocols, which are documented in painstaking detail, code is often treated as a transient artifact. The story of one lab's unversioned library dependency is a reminder that code, like any experimental material, requires careful curation. The tools exist. The challenge is to make them part of the standard practice of science.
Beyond the Lab: Systemic Solutions
While individual labs can adopt better practices, systemic changes are needed to shift the culture of computational reproducibility. Journals and funding agencies are increasingly recognizing this. For example, the National Science Foundation (NSF) now requires data management plans that include software preservation, and some journals, like Nature, have begun to ask for a "code availability" statement. However, enforcement remains weak. A 2023 study of 500 papers with code availability statements found that only about 40% of the code actually ran without errors when tested.
One promising approach is the use of "reproducibility badges" awarded by journals or third-party services. The Center for Open Science (COS) offers badges for code that has been verified to run in a controlled environment. Similarly, the journal eLife has a "reproducibility check" that tests code and data before publication. These incentives encourage researchers to adopt better practices, but they are not yet universal.
Another systemic solution is the creation of curated software archives, such as Software Heritage, which preserves source code in perpetuity. By storing the exact version of every dependency, these archives make it possible to reconstruct historical environments. For the graduate student, having access to a snapshot of the library's source code at the time of the original analysis would have been invaluable.
Ultimately, the responsibility for reproducibility is shared. Researchers must be willing to invest time in environment preservation. Journals and funders must provide the infrastructure and incentives. And the community must develop standards that are practical and scalable. The incident in one lab is a small story, but it reflects a large and growing challenge. The tools are ready; it is time to use them.