Data Quality and Validation Questions
Ensuring correctness and trust in data: validation rules, constraints, completeness/accuracy/timeliness checks, and quality frameworks. Covers designing validation into pipelines, quality gates before publishing, and handling edge cases and real-world dirty data. Central to any data engineering or analytics role.
You are asked to document the known limitations of a dataset for non-technical analysts who will build on it. What key information should this documentation include (null semantics, expected lag/freshness, known gaps or sample-size caveats, confidence level, recommended and unsupported use cases), and how would you format and keep it discoverable, for example as a data-catalog entry or a README attached to the dataset, so a new analyst finds it before making a mistake rather than after?
Sample Answer
Direct answer
Documentation of a dataset's known limitations for non-technical analysts should cover null semantics (what a missing value actually means for this dataset), expected lag or freshness, known gaps or sample-size caveats, an explicit confidence level, and recommended versus unsupported use cases, formatted so a new analyst finds it before building on the dataset, not after making a mistake.
Structured elaboration
- Null semantics: does a NULL in this dataset mean "genuinely unknown," "not applicable," or "not yet arrived"? These have very different implications for how an analyst should treat them, and the distinction is rarely obvious from the data alone.
- Freshness/lag: how current is the data, and does that vary by field (some columns updated hourly, others only nightly)?
- Known gaps and sample-size caveats: any known missing time periods, undersampled segments, or known-unreliable subsets, stated explicitly rather than left for an analyst to discover the hard way.
- Confidence level and recommended use: what this dataset is well-suited for versus explicitly NOT suited for (a dataset good for directional trend analysis but not precise point-in-time reporting, for example), stated as clearly as the dataset's actual strengths.
- Discoverability: attach this documentation directly to the dataset in the data catalog or as metadata visible at the point an analyst would query it, rather than in a separate document they have to know to go looking for.
Worked example
A customer-satisfaction survey dataset's limitations doc states: "NULL in response_score means the respondent was shown the question but did not answer, not that they were never asked; response rate varies significantly by channel (68% email, 12% in-app), so channel-level comparisons of raw response counts will be misleading without normalizing by send volume; data before March 2024 uses a different 5-point scale rather than the current 10-point scale and is not directly comparable without an explicit rescaling; recommended for directional trend analysis, not appropriate as a precise measure of absolute satisfaction level for any single period." An analyst who reads this before building a quarter-over-quarter trend chart avoids a specific, predictable mistake (comparing raw scores across the 2024 scale change) that the doc calls out explicitly.
Trade-offs and pitfalls
Documentation that is accurate but buried (a wiki page nobody links to from the dataset itself) provides essentially none of its intended value, since an analyst who does not know to look for it will make exactly the mistake the documentation was written to prevent. The format matters as much as the content: attaching the caveats directly to the dataset's catalog entry, ideally surfaced in the query tool itself, is what actually changes analyst behavior, versus a separate document that exists but is never consulted.
When a validation rule fails on incoming data, you generally have three options: quarantine the offending records for review, reject the entire batch, or auto-correct (impute or coerce) and continue. Give three decision criteria for choosing between them, and design the quarantine-and-replay mechanism itself: how rejected records are captured with a structured error reason, searched, and safely re-injected once corrected.
Sample Answer
Direct answer
Choosing between quarantining, rejecting the whole batch, or auto-correcting on a validation failure comes down to three criteria: how business-critical the affected field is, whether the failure looks isolated (a handful of rows) or systemic (a large fraction of the batch, suggesting an upstream break), and the cost of a false rejection relative to the cost of letting a bad record through.
Structured elaboration
- A high-criticality field (a financial amount, a primary key) failing validation should default toward quarantine or full-batch rejection, never silent auto-correction, since an auto-corrected financial number that turns out wrong is worse than a delayed one.
- An isolated failure (2% of rows fail a check) is a good candidate for quarantining just the offending records and continuing with the rest; a systemic failure (60% of rows fail) is almost always evidence of an upstream break (a schema change, a broken producer), and continuing to process the "good" 40% risks processing data from a fundamentally broken batch, so the whole batch should be rejected instead.
- Auto-correction is appropriate only for low-stakes, well-understood, mechanically-correctable issues (trimming whitespace, coercing a known date format) where the cost of a wrong auto-correction is genuinely low and reversible.
Worked example
The quarantine-and-replay mechanism itself: a rejected record is written to a quarantine table with the original raw payload, a structured error code (not just a free-text message), the check that failed, and a timestamp. An analyst or an automated fix searches the quarantine table by error code, corrects the underlying issue (either in the source system or via a documented manual correction), and re-injects the corrected record through the same validation pipeline it originally failed, so the re-injected record is validated again rather than trusted blindly on the second attempt. Concretely: a row {order_id: 4821, amount: -5.00} fails the amount > 0 check and lands in quarantine.orders_failed with error_code=NEGATIVE_AMOUNT, check_name=amount_positive, and timestamp=2026-01-14T02:00Z, alongside the original raw payload. An analyst searches the quarantine table with WHERE error_code = 'NEGATIVE_AMOUNT', determines the amount was entered with a stray minus sign in the source system, corrects amount to 5.00 there, and re-injects order_id=4821 through the same validation pipeline, where amount > 0 now passes and the record proceeds normally.
Trade-offs and pitfalls
A quarantine-and-replay system that lets corrected records skip re-validation on their way back in defeats the purpose of quarantining them in the first place, since a manual correction is itself a source of human error. The other common pitfall is quarantining records with only a vague error message ("validation failed"), which makes the search-and-correct step slow and expensive; a structured, categorized error code is what makes quarantine practically usable at any real volume rather than becoming a write-only graveyard nobody actually processes.
You have limited engineering capacity and a backlog of data-quality issues with varying severity and varying business impact, and multiple teams are each requesting their own fix be prioritized first. Describe a prioritization framework you would use to decide what to work on next, and how you would build cross-team alignment and commitment for a shared solution (for example a common validation framework) rather than everyone patching their own pipeline independently.
Sample Answer
Direct answer
With limited engineering capacity and a backlog of data-quality issues of varying severity, prioritize using a framework that weighs business impact, likelihood of recurrence, and ease of fix together, rather than working purely by reported severity or purely by whichever issue is loudest, and build cross-team alignment around a shared solution by making the cost of NOT solving it collectively visible to everyone who would otherwise keep patching their own symptom independently.
Structured elaboration
- Prioritization framework: score each issue on business impact (revenue, trust, or compliance risk if unaddressed), likelihood of recurrence (a one-time fluke versus a systemic pattern likely to keep causing incidents), and ease of fix (quick win versus multi-quarter investment), and use the combination, not any single dimension alone, since a high-impact-but-nearly-impossible-to-fix issue and a low-impact-but-trivial-to-fix issue both deserve very different treatment than a mid-impact, systemic, moderately-hard-to-fix issue that might actually be the highest-leverage item on the list.
- Building cross-team alignment: when multiple teams each want their own fix prioritized, the highest-leverage move is often identifying that several teams' individually-requested fixes are actually symptoms of the same underlying, systemic root cause (a shared schema-registry gap, a missing common validation framework); making that shared root cause visible reframes the conversation from "whose fix goes first" to "let's jointly fund the one fix that helps everyone," which is a fundamentally easier negotiation.
- Getting commitment without direct authority: bring data, not opinions, to the prioritization conversation (quantified incident counts, quantified business impact per team) and let the shared, objective picture do the persuading, rather than relying on personal influence alone.
Worked example
Three different teams each separately request their own data-quality fix be prioritized this quarter. Digging into the actual root cause of all three reveals they all stem from the same underlying gap: no shared schema-registry enforcement across producer teams. Reframing the ask from three competing, team-specific requests into one shared infrastructure investment, with each team's incident history used as concrete evidence of the collective cost of not fixing it, turns three competing priorities into one aligned, jointly-funded initiative that serves all three teams' actual underlying need. Scoring this alongside two other backlog items on a simple 1 (low) to 3 (high) scale per dimension, and summing the three scores, makes the trade-off concrete rather than just narrated:
| Issue | Business impact | Recurrence likelihood | Ease of fix | Total score |
|---|---|---|---|---|
| Shared schema-registry gap (all 3 teams) | High (3) | High (3), systemic | Hard (1), multi-quarter | 7 |
| One-time vendor bad-file incident | Medium (2) | Low (1), a fluke | Easy (3), quick patch | 6 |
| Cosmetic dashboard label bug | Low (1) | Low (1) | Easy (3), quick patch | 5 |
The schema-registry gap wins the priority order (7, then 6, then 5) precisely because it combines high impact with high recurrence, even though it is the hardest of the three to fix, which is the case the framework is built to catch: scoring on ease of fix alone would have wrongly ranked the two quick patches above the systemic, harder, but far higher-leverage fix.
Trade-offs and pitfalls
The temptation under pressure is to simply work the backlog in the order requests arrived, or to prioritize whichever team is loudest, both of which systematically under-invest in quieter-but-higher-leverage systemic fixes in favor of whoever advocates hardest for their specific, narrower issue. A framework that explicitly scores business impact and recurrence likelihood, and actively looks for shared root causes across seemingly-separate requests, protects against exactly that bias.
Create a documentation template for a data-quality rule that both analysts and engineers can use: what fields would you include (description, detection logic, severity, owner, remediation steps, and worked examples of a passing and failing record), where would you store it so it stays discoverable and current as pipelines evolve, and how would you version it so consumers can see the rule's history?
Sample Answer
Direct answer
A data-quality rule documentation template needs, at minimum: a plain-language description, the detection logic (the actual query or code implementing the check), severity, an owner, remediation steps, and worked examples of both a passing and a failing record, stored somewhere discoverable and versioned so it stays accurate as the underlying pipeline evolves.
Structured elaboration
- Description: a plain-language statement of what the rule checks and why it matters, written for someone who is not the rule's author.
- Detection logic: the literal, runnable check (SQL, a framework expectation, a script), not a paraphrase of it, so anyone can verify exactly what is being tested rather than relying on the description alone, which can drift out of sync with the actual implementation.
- Severity and owner: an explicit escalation path, who gets paged, and how urgently, when this rule fails.
- Remediation steps: what to actually do when the rule fires, not just what the rule detects; a rule with no documented remediation path is only half-useful.
- Worked examples: a concrete passing record and a concrete failing record, since an abstract description of "what counts as a violation" is often ambiguous at the edges in a way a real example resolves immediately.
- Discoverability and staying current: store the template alongside the pipeline code itself (versioned in the same repository) rather than in a separate wiki that drifts out of sync, and treat a change to the detection logic as requiring an update to the documentation in the same code review, not as a separate, easily-forgotten step.
Worked example
A rule for "duplicate order detection": description = "flags orders with the same (customer_id, order_total, order_date) appearing more than once, which usually indicates a retry-induced duplicate insert rather than a genuine repeat purchase"; detection logic, inlined rather than just referenced, so the documentation and the runnable check are the same artifact:
WITH ranked AS (
SELECT order_id, customer_id, order_total, order_date, created_at,
ROW_NUMBER() OVER (
PARTITION BY customer_id, order_total, order_date
ORDER BY created_at
) AS rn
FROM orders
)
SELECT * FROM ranked WHERE rn > 1;
Every row this returns has rn > 1, meaning it is not the first-created row within its (customer_id, order_total, order_date) group, so it is flagged as a probable duplicate rather than the original; severity = medium, does not block the pipeline, routes to a daily digest rather than paging; owner = the orders-pipeline team; remediation = "confirm via the source system's request ID whether this is a genuine retry duplicate, and if so, mark the later record for exclusion in the next reconciliation pass"; worked examples = one clearly-duplicate pair and one legitimate same-day repeat purchase that should NOT be flagged, illustrating exactly where the boundary of the rule lies.
Trade-offs and pitfalls
The template's biggest practical risk is documentation drift: a rule's underlying SQL gets updated during an incident fix, but the corresponding documentation is not, and six months later the documented detection logic no longer matches what actually runs, misleading whoever reads it next. Requiring the documentation update as part of the same pull request that changes the detection logic, enforced by convention or by a lightweight CI check, is what actually keeps the two in sync rather than relying on someone remembering to update a separate wiki page.
You receive an unfamiliar dataset from a partner team or a new source you've never seen. What are your first ten actions to profile and validate it before anyone uses it in reports or models? Include the quick checks you'd run first, the deeper validations you'd follow up with, and how you'd document initial findings for stakeholders.
Sample Answer
Direct answer
Ten concrete first actions, roughly in order: confirm row count and schema against what you were told to expect; check dtypes per column; compute null rate and duplicate-row count; look at min/max and a few percentiles for every numeric column; get distinct-value counts and top values for every categorical column; spot-check a sample of raw rows by eye; verify any key or ID column is actually unique if it's supposed to be; check date ranges for anything out-of-bounds (future dates, dates before the business existed); look for an obviously wrong unit or scale (cents vs dollars, seconds vs milliseconds); and write down the three or four things that most surprised you.
Walking through the actions
The first few actions are about trust, not insight: does the file even match the schema you were promised, and does anything look mechanically broken (a column that's supposed to be numeric but parses as text, a primary key with duplicates)? Only once those pass do you move to the "deeper validations": distributions per column, cross-checks between related columns (does end_date ever come before start_date?), and a manual read of 20 to 30 raw rows, which catches things summary statistics hide, like a free-text field that's actually three fields crammed together.
Worked example
A partner team sends a transactions export. Your first ten actions surface: the file has 120,000 rows against an expected ~118,000 (close enough, likely fine); transaction_id is unique as expected; amount ranges from -450 to 9,800, and the negative values turn out to be refunds, not errors, once you check the type column; country has 4 spellings of "United States"; and 3% of rows have a customer_id of exactly 0, which your manual read reveals is a placeholder for guest checkouts, not a missing value. None of that required modeling, just a disciplined first pass.
Documenting findings for stakeholders
The tenth action, writing down what surprised you, only helps the rest of the organization if it turns into an actual artifact someone besides you reads, not notes left in your own scratch file. A concrete version for the transactions export above: post a short message (to the requesting team's channel, or a short doc linked from the ticket that asked for the dataset) with one line per finding, stating what was checked, what was found, and whether it blocks use, before the dataset is used in any report or model. For example: "Row count: 120,000 vs. ~118,000 expected, within normal variance, not a blocker. Amount: ranges from -450 to 9,800; negative values are refunds confirmed via the type column, not data errors, not a blocker. Country: 4 distinct spellings of United States, needs normalization before any country-level rollup, blocks country-level grouping until fixed. customer_id: 3% of rows are exactly 0, confirmed as a guest-checkout placeholder rather than a missing value, not a blocker but should be flagged so downstream users don't mistake it for bad data and drop those rows." A findings summary in this one-line-per-finding, found-plus-blocking-status shape lets the requesting team decide, per finding, whether to use the data as-is, wait for a fix, or work around a known quirk, instead of each downstream consumer rediscovering the same quirks independently after something is already wrong in a report.
Trade-offs and pitfalls
Time-box this: a "first ten actions" pass is meant to take an hour or two, not a day. If a check surfaces something that needs deeper investigation (like the guest-checkout placeholder above), note it and move on rather than resolving it inline, so you get through the full breadth of checks before diving deep on any one of them. The other pitfall is skipping the manual row-by-row read because it feels unscientific: automated summary statistics won't catch a genuinely weird encoding the way ten minutes of eyeballing raw rows will.
Unlock Full Question Bank
Get access to all 32 Data Quality and Validation interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.