Understanding Sanity Checks


Oluwole Dada
June 26th, 2025
5 Min Read
When building software or working with data, things often go wrong in subtle ways. A script crashes halfway. An app behaves strangely. A dashboard shows negative sales numbers. And many times, the root cause is surprisingly basic, such as a missing file, an unset variable, or an assumption that quietly breaks. That's where sanity checks come in.
Not all bugs come from deep logical errors or broken dependencies. Sometimes, systems fail because something simple was overlooked.
Sanity checks are like quick mental tests you run in your code to ask, "Does this even make sense?" They are not full test suites or deep validation systems. They are small checks that help you avoid wasting time or making things worse by continuing with bad data or broken assumptions.
They are very useful in environments where assumptions can silently fail. This includes deployments, user input handling, third-party APIs, and dynamic configuration. In these situations, the goal is not to prove correctness, but to ensure the system is in a state where correctness is even possible.
Laravel: Checking Mail Config
Consider a Laravel application that sends emails through a transactional email service such as Postmark or Mailgun. The system depends on configuration values like MAIL_FROM_ADDRESS and API tokens. If any of these are missing or incorrect, failures may not be obvious at first. Jobs may fail silently, or errors may only appear much later.
A sanity check makes that assumption explicit:
if (empty(config('mail.from.address'))) {
throw new RuntimeException('Sanity check failed: MAIL_FROM_ADDRESS is not set.');
}
if (empty(config('services.postmark.token'))) {
throw new RuntimeException('Sanity check failed: POSTMARK_TOKEN is missing.');
}This does not verify that email delivery works. It is simply ensuring that the system is not attempting to send emails without the required configuration. Failing early avoids deeper, more confusing failures later.
JavaScript: Validating Inputs and Environment
The same idea applies in JavaScript, especially when dealing with user input or runtime configuration.
For example, a frontend form that collects ratings:
if (
typeof form.rating !== 'number' ||
form.rating < 1 ||
form.rating > 5
) {
throw new Error('Sanity check failed: Rating must be a number between 1 and 5.')
}This does not guarantee that the input is meaningful, but it clearly prevents invalid data from being processed.
In a Node.js environment, configuration assumptions are just as important:
if (!process.env.DATABASE_URL) {
console.error("Sanity check failed: DATABASE_URL is missing.");
process.exit(1);
}Here, the system refuses to start unless the required environment variable is set. This avoids running an application that is guaranteed to fail once it tries to access the database.
CI/CD Pipelines: Catching Deployment Issues Early
CI/CD pipelines introduce another layer of complexity. They run quickly, often without direct human oversight, and depend heavily on configuration and environment setup.
In these environments, small oversights can lead to broken deployments or partially working systems. Sanity checks serve as a safeguard, verifying that critical components are in place before deployment proceeds.
For example, checking for a required environment file:
- name: Check .env file
run: |
if [ ! -f ".env.production" ]; then
echo "Sanity check failed: .env.production file is missing."
exit 1
fiOr ensuring that build artifacts exist:
[ ! -s "public/js/app.js" ] && echo "Sanity check failed: app.js is empty or missing." && exit 1These checks do not validate the correctness of the build. They confirm that something essential has not been skipped or lost in the process.
Local Development: Preventing Confusion Early
Sanity checks are just as useful during development. Local environments often vary between developers, and small differences can lead to confusing issues.
A simple check can prevent running code in the wrong environment:
if (app()->environment('production') && empty(config('app.url'))) {
throw new RuntimeException('Sanity check failed: APP_URL must be defined in production.');
}if (process.env.NODE_ENV !== 'development') {
throw new Error('Sanity check failed: This should only run in development mode.');
}These checks reduce ambiguity. Instead of debugging unexpected behaviour, developers get immediate feedback about what is wrong.
When Sanity Checks Become a Problem
Sanity checks are helpful, but they can also be misused.
If checks are too vague, such as if (!data) without explaining what data should contain, they provide little value. They can even be misleading. A failure may appear to be a bug in the logic rather than a missing assumption.
The effectiveness of a sanity check depends on clarity. It should make both the assumption and the failure obvious.
A Simple Principle
Sanity checks are not about making systems perfect. They are about preventing avoidable mistakes.
They help you fail early, reduce debugging time, and make assumptions explicit. They do not replace tests. Unit tests confirm that logic behaves correctly. Sanity checks confirm that the system is in a state where that logic can even run.
A good sanity check is like turning on the lights before entering a room. It does not fix anything. It simply shows what is there.
And sometimes, that is all you need to avoid stepping on something sharp.
Read More Articles
From Loops to Pipelines: Designing Declarative Data Flows in JavaScript

From Loops to Pipelines: Designing Declarative Data Flows in JavaScript
How JavaScript’s array methods come together to form declarative data pipelines that prioritise readability, composition, and intentional flow.
October 31st, 2025
7 Min Read
The Forgotten Array Methods: Gems Hidden in Plain Sight

The Forgotten Array Methods: Gems Hidden in Plain Sight
How lesser-known JavaScript array methods reveal expressive patterns and help write clearer, more intentional code without added complexity.
October 31st, 2025
5 Min Read