CertSafari
    Databricks Certified Data Engineer Professional - October 9 onwards· Lessons

    Domain 3 · Lesson 21/46

    Quarantining Invalid Records and Grouping Pipeline Expectations

    Implement data quality expectations in Lakeflow Declarative Pipelines to quarantine, drop, or fail on bad records.

    10 min read
    3% of exam
    5 sources
    Published 2 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Apply a group of expectations with one collective action using the expect_all decorators
    • Store expectation rules centrally and reuse them across datasets
    • Build a quarantine pattern that keeps invalid rows for investigation instead of discarding them
    • Choose warn, drop, quarantine, or fail for each constraint, and know when a job is needed to gate downstream work

    1.Applying a set of rules at once with expect_all

    Real datasets rarely have only one rule. SQL and Python both let you put several expectations on a dataset, but only Python lets you group them and give the whole group one action. The decorators are expect_all, expect_all_or_drop and expect_all_or_fail. Each takes a Python dictionary in which every key is an expectation name and every value is its constraint.

    Grouping doesn't hide detail. Each expectation in the dictionary keeps its own description and reports its own metrics, so you can still see which rule a record broke. Because the dictionary is an ordinary Python object, you can apply one rule set to several datasets with different strictness.

    One rule set applied with warn, drop and fail semantics to three datasetspython
    valid_pages = {"valid_count": "count > 0", "valid_current_page": "current_page_id IS NOT NULL AND current_page_title IS NOT NULL"}
    
    @dp.table
    @dp.expect_all(valid_pages)
    def raw_data():
      # Create a raw dataset
    
    @dp.table
    @dp.expect_all_or_drop(valid_pages)
    def prepared_data():
      # Create a cleaned and prepared dataset
    
    @dp.table
    @dp.expect_all_or_fail(valid_pages)
    def customer_facing_data():
      # Create cleaned and prepared to share the dataset

    Checkpoint 1 of 5· Check yourself

    A SQL-only team wants to declare a group of five constraints once and give the whole group the DROP action. What is true?

    Sources12

    2.Keeping rules outside the pipeline code

    Because expect_all takes a dictionary, the rules can come from somewhere other than the pipeline source. Databricks recommends storing expectation definitions separately from pipeline logic, tagging related expectations so you can filter them, and applying the same expectations to similar datasets.

    The documented pattern keeps a rules Delta table, or a Python module such as rules_module.py, with a name, a constraint and a tag for each rule. A helper get_rules(tag) returns a {name: constraint} dictionary for one tag. For example, @dp.expect_all_or_drop(get_rules('validity')) drops records from raw_farmers_market that fail any rule tagged validity. You can then audit or change the rules without editing the pipeline code. This approach is Python-only: SQL cannot load expectations dynamically from a file.

    Checkpoint 2 of 5· Check yourself

    Which statement about central rule repositories for expectations is correct?

    Sources3

    3.Quarantine: keep bad rows without letting them through

    There isn't. Quarantine is a pattern you build from datasets and flows, not a fourth action. The expectations docs describe it as advanced logic to quarantine invalid records without failing or dropping data. It solves drop's weakness: dropped rows are counted, but they are gone, so nobody can look at them or reprocess them.

    The best-practices guide describes it with two flows. One flow drops invalid rows from the main table. A second flow writes only the invalid rows to a separate quarantine streaming table. You can then investigate, fix and reprocess the bad data without contaminating the clean dataset.

    The advanced-patterns page shows a version built on a flag column. A rules dictionary holds the constraints, and quarantine_rules combines them into one NOT(... AND ...) expression. A temporary table applies the rules with expect_all, so you get per-rule metrics without dropping anything. It also adds an is_quarantined column calculated from the combined expression and is partitioned on that column. Views downstream split the table into valid and invalid rows.

    Quarantine with a flag column: warn-level metrics plus an is_quarantined column, then a view of the valid rowspython
    quarantine_rules = "NOT({0})".format(" AND ".join(rules.values()))
    
    @dp.view
    def raw_trips_data():
      return spark.readStream.table("samples.nyctaxi.trips")
    
    @dp.table(
      temporary=True,
      partition_cols=["is_quarantined"],
    )
    @dp.expect_all(rules)
    def trips_data_quarantine():
      return (
        spark.readStream.table("raw_trips_data").withColumn("is_quarantined", expr(quarantine_rules))
      )
    
    @dp.view
    def valid_trips_data():
      return spark.read.table("trips_data_quarantine").filter("is_quarantined=false")

    Checkpoint 3 of 5· Check yourself

    Analysts must be able to inspect and reprocess malformed orders, but the clean orders table must never contain them. Which approach meets both needs?

    Checkpoint 4 of 5· Exam question

    A data engineer is building a silver-layer streaming table in a Lakeflow Declarative Pipeline. The business requirement states that records with a null `customer_id` must never reach the silver table, but the pipeline should keep processing subsequent batches even when such records occur, and the team wants a running count of how many rows were removed. Which decorator should the engineer apply to the transformation function?

    Sources243

    4.Choosing an action per constraint, and what expectations can't do

    The production-readiness checklist asks you to choose the action for each constraint on purpose, not to apply one action everywhere. Use fail for conditions that should stop everything, such as a broken primary key. Use drop for records you can safely discard, with a quarantine table capturing what was dropped. Use warn only where you actively watch the trend. The checklist also expects every dataset that can receive bad data to have at least one expectation, and you to know its current pass rate from the Data quality tab or the event log.

    Matching the action to your tolerance for bad data
    SituationAction
    Condition that should stop the world, such as a broken primary keyfail (expect_or_fail / ON VIOLATION FAIL UPDATE)
    Records you can safely discarddrop (expect_or_drop / ON VIOLATION DROP ROW), plus a quarantine table
    You need all data but want to see quality trends you actively watchwarn (expect / bare EXPECT)

    One limit catches people out. Expectations enforce data quality, not orchestration. They decide which records reach a target, but they don't conditionally run or skip other parts of the pipeline. You can build a validation table, such as a materialized view comparing row counts with expect_or_fail("no_rows_dropped", "a_count == b_count"). But a dataset that reads it does not wait for its result, so a failed validation does not stop downstream tables from updating. To gate downstream work, put the validation and the downstream logic in separate pipelines. Then orchestrate them with a job in which the downstream task depends on the validation task.

    Checkpoint 5 of 5· Check yourself

    A pipeline has a validation materialized view with expect_or_fail, and a reporting table in the same pipeline reads from it. The validation fails in a triggered run. Is the reporting table update blocked?

    Sources53

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Quarantine is a built-in expectation action, like DROP ROW or FAIL UPDATE.Why is that wrong?

      There are only three actions: warn, drop and fail. Quarantine is a pattern built from extra flows or a flag column with views that route valid and invalid records separately.

      Covered in Quarantine: keep bad rows without letting them through

    2. 2.A failing validation table with expect_or_fail stops downstream tables in the same pipeline from updating.Why is that wrong?

      Expectations don't orchestrate. To gate downstream work, split it into a separate pipeline that runs only after the validation pipeline's task succeeds in a job.

      Covered in Choosing an action per constraint, and what expectations can't do

    3. 3.SQL can group several constraints under one collective ON VIOLATION action.Why is that wrong?

      SQL allows several constraints, but each has its own action. Only Python's expect_all, expect_all_or_drop and expect_all_or_fail apply one action to a group.

      Covered in Applying a set of rules at once with expect_all

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “When you use expect_all decorators, each expectation has its own description and reports granular metrics.”
      ↩︎ Applying a set of rules at once with expect_all
    2. 2.
      “only Python allows you to group multiple expectations and specify collective actions.”
      ↩︎ Applying a set of rules at once with expect_all
      “You can also implement advanced logic to quarantine invalid records without failing or dropping data.”
      ↩︎ Quarantine: keep bad rows without letting them through
      “only Python allows you to group multiple expectations and specify collective actions.”
      ↩︎ Exam trap 3
    3. 3.
      “Store expectation definitions separately from pipeline logic.”
      ↩︎ Keeping rules outside the pipeline code
      “Dynamically loading expectations from a file is not supported in SQL.”
      ↩︎ Keeping rules outside the pipeline code
      “enable separate processing paths for valid and invalid records in downstream operations”
      ↩︎ Quarantine: keep bad rows without letting them through
      “Expectations enforce data quality, not orchestration.”
      ↩︎ Choosing an action per constraint, and what expectations can't do
      “enable separate processing paths for valid and invalid records in downstream operations”
      ↩︎ Exam trap 1
      “A validation table doesn't gate its downstream tables.”
      ↩︎ Exam trap 2
      “A validation table doesn't gate its downstream tables.”
      ↩︎ Checkpoint
    4. 4.
      “This lets you investigate, fix, and reprocess bad data without contaminating your clean dataset.”
      ↩︎ Quarantine: keep bad rows without letting them through
      “Route rows that fail validation to a separate streaming table by using two flows”
      ↩︎ Checkpoint
    5. 5.
      “drop for records you can safely discard (with a quarantine table capturing what was dropped), and warn only where you actively watch the trend.”
      ↩︎ Choosing an action per constraint, and what expectations can't do
      “fail for conditions that should stop the world (such as a broken primary key)”
      ↩︎ Choosing an action per constraint, and what expectations can't do

    Spotted a mistake, or was something unclear? Tell us.