A machine learning model can score extremely well in offline evaluation and fail as soon as it reaches production. Sometimes the model is not the main problem. The evaluation accidentally gave it information that would not exist when a real prediction is made.

This failure is called target leakage: information related to the outcome enters the model inputs in a way that makes the target easier to predict than it will be at inference time. Leakage can produce impressive metrics because the model is solving an easier, unrealistic problem.

For developers, the practical rule is simple: every feature used to make a prediction must be justified from the perspective of the moment that prediction is made. This article builds that mental model, shows common leakage paths, and explains how to design evaluation so that offline performance remains meaningful.

Think from the prediction timestamp

Suppose a support system predicts whether a newly opened ticket will eventually be escalated.

At prediction time, these fields are available:

created_at
customer_plan
initial_message
product_area

Later, after agents have worked on the ticket, the record may also contain:

resolution_time
number_of_agent_replies
escalation_team
final_status

If the training table includes escalation_team, a classifier may learn that tickets routed to the escalation team are usually escalated. That relationship is real, but it is useless for the intended prediction because routing happens after the prediction should have been made.

The right question is therefore not:

Is this column correlated with the target?

It is:

Could this exact value be known when the production system must make the prediction?

That question catches many leakage problems before model training begins.

Leakage changes the task being evaluated

Consider a binary target:

will_escalate = 1 or 0

A legitimate feature such as customer_plan may contain useful but incomplete evidence. A leaked feature such as escalation_team may reveal a downstream action that is strongly determined by the outcome.

The model then learns something closer to:

infer escalation from evidence created after escalation became known

instead of:

predict future escalation from information available when the ticket arrives

Both computations can produce valid numbers on a held-out dataset. Only the second matches the production task.

This is why a conventional train/test split does not automatically prevent leakage. If both partitions contain the same invalid feature-generation process, the test set faithfully measures performance on the wrong problem.

Common leakage paths

Leakage is often less obvious than a column named final_status.

Features computed with future information

Imagine predicting whether an account will churn during the next 30 days. A feature called payments_last_90_days is safe only if its 90-day window ends at the prediction timestamp.

If an offline pipeline computes the feature using the latest database state, some training rows may include payments that occurred after their historical prediction dates. The feature name looks reasonable, but its time boundary is wrong.

A useful representation is:

prediction time: T

allowed feature history:  <---------------- T
prediction outcome:                         T -------> future

Feature computation for a historical example should behave as if data after T does not exist.

Target-derived preprocessing

Leakage can also enter before model training.

Suppose a feature-selection step examines the entire labeled dataset, including the future test partition, and chooses variables based on their relationship with the target. The final model may never directly see test labels, yet those labels influenced which inputs were selected.

The same principle applies to supervised transformations and other preprocessing steps that learn from labels: fit them using the training data for each evaluation split, not using the evaluation labels.

Unsupervised preprocessing deserves similar care for a different reason. Fitting a normalizer on the full dataset does not directly expose target labels, but it still lets information from the evaluation partition influence training. Keeping learned preprocessing inside the training pipeline avoids this contamination and better reproduces how a new model would be fitted.

Aggregates that include the row being predicted

Aggregated features can leak information even when they use historical-looking data.

Suppose each training row is a transaction and the target indicates fraud. You create a merchant feature:

merchant_fraud_rate

If the rate is calculated from all rows, the target of the current transaction contributes to its own feature. For a merchant with very few transactions, that contribution can be substantial.

A safer training construction excludes the current target and, for time-dependent applications, uses only observations that would have been known before the prediction timestamp. Validation and test features must be generated without using their labels.

Random splits that violate time or entity boundaries

A random split is appropriate only when it represents how future examples will arrive.

For example, suppose multiple medical images belong to the same patient. If images from one patient appear in both training and test sets, the model may exploit patient-specific similarities. The resulting metric can overstate performance for the real task of predicting on unseen patients.

Likewise, when a model will predict future events, a random split can mix later records into training and earlier records into testing. A chronological split is often a better simulation of deployment when time changes what information is available or how the data is distributed.

These cases are sometimes described more broadly as data leakage rather than target leakage. The useful engineering principle is the same: the evaluation set must not provide information that the training procedure or features would lack in the intended deployment scenario.

Build features as of a historical cutoff

A robust feature pipeline gives every training example a prediction timestamp and constructs features relative to it.

For a ticket created at 2026-05-10 09:00, the offline feature builder should answer questions such as:

customer tickets before 2026-05-10 09:00
account age at 2026-05-10 09:00
plan active at 2026-05-10 09:00
message known at 2026-05-10 09:00

It should not silently substitute today’s account state or include events that happened later.

Conceptually:

for each historical example:
    T = prediction_timestamp(example)
    features = build_features(data_available_at_or_before(T))
    target = observe_outcome_after(T)

This is simplified pseudocode, not a production implementation. Real systems must define whether events exactly at T are available, account for ingestion delays, and reproduce the data sources used by online inference.

Those details matter. A database event timestamp may say when an event happened, while the serving system could only observe it several minutes later. If the model requires information that had not yet arrived, the offline feature is still unrealistic.

Split before fitting learned transformations

Evaluation should isolate the data used to estimate model behavior.

A safe high-level sequence is:

1. define train and evaluation partitions
2. fit learned preprocessing on training data
3. transform training data
4. transform evaluation data with the fitted preprocessing
5. train the model on training data
6. evaluate once on the untouched evaluation targets

When cross-validation is used, learned preprocessing should be fitted separately inside each training fold. Otherwise, information from a validation fold can influence the transformation applied during training.

This is one reason pipeline abstractions are useful in machine learning libraries: they can keep fitting steps attached to the training partition rather than requiring developers to remember the boundary manually.

The exact API depends on the library. The invariant does not: evaluation data must not participate in learning the model or supervised preprocessing that is supposed to be learned from training data alone.

Use suspiciously good performance as a debugging signal

Leakage does not always produce near-perfect accuracy, but unexpectedly strong results should trigger investigation.

Suppose a baseline classifier reaches an F1 score of 0.62. Adding one operational field raises it to 0.96. That improvement might be genuine, but it deserves questions before celebration:

  • When is the new field created?
  • Can it change after the prediction timestamp?
  • Is it directly or indirectly derived from the target?
  • Does its computation use evaluation labels?
  • Will the same value exist with the same semantics in production?

Feature ablation is useful here. Remove the suspicious feature or feature group and measure how performance changes. Also inspect simple relationships between individual features and the target. A single feature that nearly reconstructs the label may reveal a business-process artifact rather than a powerful predictive signal.

Do not assume that a modest metric rules leakage out. Weak leakage can still bias model selection and make one approach appear better than another.

Validate the whole prediction pipeline

Checking model inputs is necessary but not sufficient. Leakage can occur anywhere that evaluation information influences a training decision.

Review the pipeline in the order data flows through it:

raw events
   -> historical cutoff
   -> feature construction
   -> dataset split
   -> learned preprocessing
   -> model fitting
   -> threshold or model selection
   -> final evaluation

Each arrow is a boundary where information can cross in the wrong direction.

For example, repeatedly tuning hyperparameters against the final test set turns that test set into part of the development process. The model parameters may not be fitted on those examples, but engineering decisions become adapted to their outcomes. Use validation data for iteration and reserve a final test set for an assessment that has not guided model development.

Similarly, if a decision threshold is selected to maximize a metric, choose it on training or validation data according to the evaluation design. Measuring the chosen threshold on the same data used to optimize it gives an optimistic estimate.

Leakage prevention can require stricter evaluation

A more realistic split often lowers reported performance. That is not a defect in the evaluation.

A chronological split may be harder than a random split because future behavior differs from past behavior. Grouping all records for an entity into one partition may remove easy similarities. Rebuilding historical features with proper cutoffs may eliminate information that made prediction artificially simple.

The lower number is useful because it better represents the intended task.

There is also a cost trade-off. Point-in-time-correct feature generation can require historical snapshots, event logs, or temporal joins. For a small, low-risk model, a simpler pipeline may be appropriate if the data is genuinely static and every feature exists before prediction. Complexity should follow the actual leakage risk, not become a ritual.

Know what leakage prevention does not solve

An evaluation can be leakage-free and still be misleading.

The evaluation population may not represent production. Labels may be noisy. A chosen metric may not match the operational cost of errors. Distribution shift may occur after deployment. The model may also depend on a feature that is technically available at inference time but unreliable or expensive to obtain.

Leakage prevention solves a narrower problem: it keeps unavailable or evaluation-derived information from making offline prediction easier than the production task.

That distinction is important because it suggests the right debugging order. First make the information boundary honest. Then evaluate whether the dataset, metric, and deployment assumptions are appropriate.

Conclusion

Target leakage is best understood as a time-and-information-boundary error. A feature is not safe merely because it exists in a training table. It must be available, with the same meaning, at the moment the real system makes its prediction.

Define that moment explicitly. Build historical features as of that cutoff, keep evaluation labels out of feature construction and learned preprocessing, choose splits that match deployment, and treat unusually strong metrics as something to verify rather than automatically trust.

An honest evaluation may look less impressive, but it answers the question developers actually need: how well can the model perform using only the information it will really have?