Skip to content

dbt Test Failure: Null Customer IDs in Shipping Addresses

Date: 2025-12-07
Severity: Medium (Data Quality Test Failure)
Status: Open - Needs Decision
Component: apps/dagster/dbt/models/silver/stg_shipping_addresses.sql


The dbt test not_null_stg_shipping_addresses_customer_id is failing with 11,659 null values for connection 49fc4591-1eb5-41d7-88e7-d8a88730cd83. This causes the entire dbt_transform job to fail, even though most models and tests pass successfully.


28 of 39 FAIL 11659 not_null_stg_shipping_addresses_customer_id [FAIL 11659 in 7.50s]
Failure in test not_null_stg_shipping_addresses_customer_id (models/silver/schema.yml)
Got 11659 results, configured to fail if != 0
Done. PASS=40 WARN=0 ERROR=1 SKIP=1 NO-OP=0 TOTAL=42

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ raw_shipping_addresses β”‚ (from Iceberg/P21)
β”‚ - customer_id (often β”‚
β”‚ NULL in raw data) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ stg_shipping_addresses β”‚
β”‚ - COALESCE( β”‚
β”‚ links.erp_customer │◄──┐
β”‚ addr.customer_id) β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ LEFT JOIN β”‚
β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ stg_ship_to_links β”‚β”€β”€β”€β”˜
β”‚ - Filtered WHERE β”‚
β”‚ erp_customer_id β”‚
β”‚ IS NOT NULL β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. stg_shipping_addresses computes customer_id as:

    COALESCE(links.erp_customer_id, addr.customer_id) AS customer_id
  2. LEFT JOIN with stg_ship_to_links - If no matching link exists, links.erp_customer_id is NULL

  3. Fallback to addr.customer_id - The raw shipping address data often doesn’t have customer_id populated (it’s optional in the source ERP system)

  4. Result: 11,659 shipping addresses have NULL customer_id because:

    • No entry exists in ship_to_links for that shipping address
    • The raw shipping_addresses table has NULL customer_id

In Prophet 21 (and many ERP systems), shipping addresses can exist in two states:

  1. Ship-To Addresses - Linked to a customer via ship_to_links (have customer_id)
  2. Standalone Addresses - Created during orders but not formally linked to a customer

The dbt test assumes ALL shipping addresses must have a customer, which is too strict for this data model.


apps/dagster/dbt/models/silver/schema.yml
- name: stg_shipping_addresses
description: 'Deduplicated shipping addresses'
columns:
- name: customer_id
tests:
- not_null # ← This test is too strict

Impact Description
Job Failure The entire dbt_transform job fails even though 40 other tests pass
Downstream Effects Gold layer dim_shipping_addresses is skipped
Data Freshness Shipping address data becomes stale in Typesense

Change from hard failure to warning - allows pipeline to continue while flagging data quality issues:

- name: customer_id
tests:
- not_null:
severity: warn
config:
warn_if: '>10000' # Allow known baseline

If shipping addresses without customers are valid business data, remove the test entirely:

# Remove customer_id not_null test
- name: customer_id
description: 'Customer ID (nullable for standalone addresses)'

Assign a placeholder customer_id for orphaned addresses:

COALESCE(
links.erp_customer_id,
addr.customer_id,
'ORPHANED-' || addr.erp_shipping_id -- Fallback placeholder
) AS customer_id

Not recommended - this masks the data quality issue and creates fake IDs.

Investigate why ship_to_links doesn’t cover all shipping addresses. This may require changes to the bronze extraction.


Implement Option 1 - Change the test to a warning with a threshold.

This approach:

  • Allows the pipeline to complete successfully
  • Preserves visibility into data quality issues
  • Doesn’t mask or alter the underlying data
  • Can be fine-tuned as data quality improves

File Change
apps/dagster/dbt/models/silver/schema.yml Change not_null test severity to warn

apps/dagster/dbt/models/silver/schema.yml
- name: stg_shipping_addresses
description: 'Deduplicated shipping addresses'
columns:
# ... other columns ...
- name: customer_id
description: 'Customer ID (nullable for standalone/orphan addresses)'
tests:
- not_null:
severity: warn
config:
warn_if: '>15000' # Allow baseline + buffer
error_if: '>50000' # Alert if dramatically worse

  • Typesense sync runs successfully even when dbt fails (shipping addresses were synced: 5000 records)
  • The gold layer dim_shipping_addresses is skipped due to test failure

After implementing the fix, verify:

  1. dbt_transform job completes with warnings (not errors)
  2. dim_shipping_addresses model builds successfully
  3. Typesense sync includes shipping addresses from the gold layer