Databricks Streaming Guardian
ASecurityGuard production Databricks data pipelines — Delta Lake, Liquid Clustering, Structured Streaming, Auto Loader, and DLT — against the twelve foot-guns that fire at scale: OPTIMIZE/auto-compaction conflicts, Liquid-Clustering merge conflicts, VACUUM breaking a streaming checkpoint, RocksDB OOM, Auto Loader schema-evolution stops, and DLT refresh data loss. Includes a PreToolUse hook that blocks DROP/CREATE-OR-REPLACE/VACUUM on a table with active streaming consumers. Use when a Delta MERGE/OPTI...
- 2,719 stars
- 0 votes
- 0 copies
- 0 views
- Added September 21, 2026
Works with
Security analysis
100/100Pro scans all 14 files and shows the line behind each finding
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill databricks-streaming-guardian --agent claude-codeAre you the author of Databricks Streaming Guardian?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jeremylongshore-databricks-streaming-guardian-21cfaa8d)---
name: databricks-streaming-guardian
description: |
Guard production Databricks data pipelines — Delta Lake, Liquid Clustering,
Structured Streaming, Auto Loader, and DLT — against the twelve foot-guns that
fire at scale: OPTIMIZE/auto-compaction conflicts, Liquid-Clustering merge
conflicts, VACUUM breaking a streaming checkpoint, RocksDB OOM, Auto Loader
schema-evolution stops, and DLT refresh data loss. Includes a PreToolUse hook
that blocks DROP/CREATE-OR-REPLACE/VACUUM on a table with active streaming
consumers. Use when a Delta MERGE/OPTIMIZE fails with a concurrency exception, a
stream breaks after VACUUM or a table replace, an Auto Loader stream stops on a
new column, a DLT refresh drops data, or before running a destructive op on a
streamed-from table. Trigger with "ConcurrentAppendException",
"ConcurrentDeleteDeleteException", "DELTA_FILE_NOT_FOUND", "streaming checkpoint
broke", "vacuum broke my stream", "autoloader UnknownFieldException", "dlt full
refresh".
allowed-tools: Read, Write, Edit, Bash(databricks:*), Bash(jq:*), Bash(python3:*), Bash(bash:*), Glob, mcp__databricks-workspace-mcp__clusters_events, mcp__databricks-workspace-mcp__clusters_list, mcp__databricks-workspace-mcp__pipelines_get
version: 2.28.0
author: Jeremy Longshore <jeremy@intentsolutions.io>
license: MIT
compatibility: Designed for Claude Code
tags: [saas, databricks, streaming, delta, data-ops]
---
# Databricks Streaming Guardian
The data-ops spine of the pack. Delta Lake, Liquid Clustering, Structured
Streaming, and DLT each ship a different set of foot-guns that fire most visibly
when production data flows through them at scale — and most of them are documented
platform *decisions* that surprise engineers, not bugs. This skill's job is
friction at trigger time (a hook that blocks the genuinely-irreversible op) plus
deterministic recovery when something already broke.
## Overview
Twelve foot-guns, grouped by the surface that triggers them. Eleven are owned
outright (D01–D10, D12); the twelfth — D11, DLT rebuild cost — is shared with
`databricks-cost-leak-hunter`: this skill checks the rebuild cost as part of
pre-refresh safety, that skill owns ongoing cost optimization.
**Delta write conflicts.** D01 `ConcurrentDeleteDeleteException` — a manual
`OPTIMIZE` colliding with auto-compaction, which is silently enabled on any table
touched by `MERGE`/`UPDATE`/`DELETE`. D02 `ConcurrentAppendException` after moving
to Liquid Clustering — LC keeps file-set-level writer conflicts; a fan-out `MERGE`
breaks unless its predicate is narrowed to the clustering keys.
**Streaming + checkpoint.** D03 `DELTA_FILE_NOT_FOUND_DETAILED` — `VACUUM` deletes
files the checkpoint pins to. D04 silent checkpoint corruption / reset to batch 0.
D05 RocksDB state-store off-heap OOM (the heap looks fine while off-heap state pins
multi-GB). D12 `DIFFERENT_DELTA_TABLE_READ_BY_STREAMING_SOURCE` — `CREATE OR
REPLACE` mints a new UUID and kills every active consumer.
**Migration + evolution.** D06 Liquid-Clustering migration's hidden full-rewrite
cost + downstream partition-predicate breakage. D07 time travel breaking silently
when `VACUUM` crosses the retention boundary. D10 Auto Loader
`UnknownFieldException` stopping the stream on every new column.
**DLT.** D08 the `@dlt.table` thread race (out-of-order registration). D09 full
refresh silently dropping data from a non-replayable source. D11 the rebuild cost
multiplier (checked before a full refresh; ongoing DLT cost is
`databricks-cost-leak-hunter`'s job).
**The hook (AP02/AP06 — this pack's only blocking hook).** A `PreToolUse` hook
(`hooks/streaming-guard-hook.py`) intercepts a Bash command that runs `DROP TABLE`,
`CREATE OR REPLACE TABLE`, or `VACUUM` against a table and — only when it confirms
via `system.streaming.query_progress` that an active stream reads that table —
**blocks it** with a message naming the consumers and the pain. It is precise by
design: it matches only real SQL-execution surfaces (never a `git commit` mentioning
"drop table"), and it **fails open** — if it cannot verify consumers, it allows
rather than false-block. Blocking is reserved for the genuinely irreversible.
Deterministic work lives in `scripts/`; deep knowledge in `references/`; the
Liquid-Clustering predicate rewrite in the `merge-rewriter` subagent. Two data
planes: the `databricks-workspace-mcp` control plane (cluster/pipeline events) and
the CLI Statement Execution API for `system.*` reads. Either absent → advisory mode
on pasted input.
## Prerequisites
- **`databricks-workspace-mcp` registered** — for `clusters_events` (RocksDB OOM
correlation) and `pipelines_get` (DLT event log). Absent → advisory mode.
- **Databricks CLI** authenticated + `jq`, and **`DATABRICKS_WAREHOUSE_ID`** set —
for the `system.streaming.query_progress` reads the hook and recovery flows use.
The hook fails open (allows) if these are absent, so it never false-blocks.
- **The hook is a plugin-level `PreToolUse` hook** — it runs on Bash commands once
the pack is installed. It is silent on everything except a confirmed-unsafe
destructive op.
## Instructions
Pick the flow by symptom. **Always name the exact, searchable Databricks error
string** — `ConcurrentAppendException`, `ConcurrentDeleteDeleteException`,
`DELTA_FILE_NOT_FOUND_DETAILED`, `DIFFERENT_DELTA_TABLE_READ_BY_STREAMING_SOURCE`,
`UnknownFieldException` — even when the user paraphrases it or gives a short form;
the full code is what an operator greps logs and docs for.
### Step 1: Before a destructive op (the hook does this automatically)
Running `DROP TABLE` / `CREATE OR REPLACE TABLE` / `VACUUM` on a table? The hook
checks for active streaming consumers first and blocks if any exist. To check
manually, query `system.streaming.query_progress` for a stream whose
`source_description` names the table. If consumers exist: do NOT `CREATE OR
REPLACE` (use `ALTER`/in-place — D12) and do NOT `VACUUM` below the consumers'
checkpoint lag (D03/D07). See
[`${CLAUDE_SKILL_DIR}/references/checkpoint-recovery.md`](references/checkpoint-recovery.md).
### Step 2: A Delta write conflict (D01, D02)
- **`ConcurrentDeleteDeleteException` (D01)** — before a manual `OPTIMIZE`, probe
the table for auto-compaction:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/pre-optimize-check.sh" --table main.sales.orders
```
If it reports COLLISION RISK, don't run manual `OPTIMIZE` (or disable
auto-compaction first). Details:
[`${CLAUDE_SKILL_DIR}/references/concurrency-conflicts.md`](references/concurrency-conflicts.md).
- **`ConcurrentAppendException` on a Liquid-Clustering table (D02)** — hand the
failing `MERGE` to the **`merge-rewriter`** subagent; it fetches the target's
clustering keys via `DESCRIBE DETAIL` and narrows the `ON` predicate so writers
touch disjoint file sets.
### Step 3: A broken streaming source (D03, D04, D12)
Map the symptom to the failure class and its exact error code, then get the
recovery tier from the decision tree:
- `file-not-found` → **`DELTA_FILE_NOT_FOUND_DETAILED`** (VACUUM deleted pinned files — D03)
- `uuid-changed` → **`DIFFERENT_DELTA_TABLE_READ_BY_STREAMING_SOURCE`** (CREATE OR REPLACE minted a new UUID — D12)
- `checkpoint-reset` → silent batchId regression / checkpoint corruption (D04)
- `transient` → a restartable blip with an intact checkpoint
```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/recover-streaming-source.py" \
--failure file-not-found --time-travel yes # or uuid-changed / checkpoint-reset / transient
```
It echoes the canonical error code and recommends SAFE_RESTART /
REPROCESS_FROM_OFFSET / RESTORE_FROM_TIME_TRAVEL / FULL_RESET_BACKFILL with the
data-loss tradeoff stated up front. Name that full code in your answer — not just
the short class. The full
three-tier reasoning is in
[`${CLAUDE_SKILL_DIR}/references/checkpoint-recovery.md`](references/checkpoint-recovery.md).
### Step 4: RocksDB state-store OOM (D05)
A driver/executor OOM while the JVM heap looks healthy points at off-heap RocksDB
state. Correlate the OOM to state size with `clusters_events`, then bound the
memory and enable changelog checkpointing per
[`${CLAUDE_SKILL_DIR}/references/rocksdb-state-store-tuning.md`](references/rocksdb-state-store-tuning.md).
### Step 5: Auto Loader schema evolution (D10)
A stream stopping with `UnknownFieldException` on a new column is the default
`addNewColumns` mode. Choose the mode deliberately (evolve-and-restart vs
`rescue`'s silent widening) and pin types with `schemaHints` per
[`${CLAUDE_SKILL_DIR}/references/autoloader-schema-evolution.md`](references/autoloader-schema-evolution.md).
### Step 6: DLT rebuild safety (D08, D09, D11)
Before a DLT full refresh, confirm every source is replayable (a Kafka topic past
retention or a truncate-and-load source loses data on refresh — D09) and that
`@dlt.table` registration is deterministic (the thread race — D08). Read the DLT
event log with `pipelines_get`; the checklist is in
[`${CLAUDE_SKILL_DIR}/references/dlt-rebuild-safety.md`](references/dlt-rebuild-safety.md).
## Output
- **A hook decision** — a destructive op on a streamed-from table is blocked with
the active consumers named and the pain (D12 / D03-D07) explained; everything
else passes silently.
- **A pre-OPTIMIZE verdict** — SAFE or COLLISION RISK (auto-compaction on) with the
disable-or-serialize fix.
- **A rewritten MERGE** — the LC clustering-key-scoped predicate (from
`merge-rewriter`) that stops `ConcurrentAppendException`.
- **A recovery recommendation** — the recovery tier + steps + the data-loss risk,
for the specific failure class.
- **A tuning / mode / refresh-safety recommendation** — RocksDB bounds, Auto Loader
mode, or the DLT full-refresh checklist, from the matching reference.
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| `ConcurrentDeleteDeleteException` | Manual OPTIMIZE races auto-compaction (D01) | Run `pre-optimize-check.sh`; don't manually OPTIMIZE an auto-compacted table, or disable auto-compact first. |
| `ConcurrentAppendException` on an LC table | MERGE predicate not scoped to clustering keys (D02) | Route the MERGE to `merge-rewriter`; narrow the ON predicate to the clustering keys. |
| `DELTA_FILE_NOT_FOUND_DETAILED` | VACUUM deleted checkpoint-pinned files (D03) | `recover-streaming-source.py --failure file-not-found`; restore via time travel if in retention, else reprocess/reset. |
| `DIFFERENT_DELTA_TABLE_READ_BY_STREAMING_SOURCE` | CREATE OR REPLACE minted a new UUID (D12) | The old checkpoint is dead — new checkpoint + backfill; the hook prevents this going forward. |
| Driver OOM, heap looks fine | Off-heap RocksDB state (D05) | Bound state-store memory + changelog checkpointing; size state with a watermark. |
| `UnknownFieldException`, stream stopped | Auto Loader `addNewColumns` default (D10) | Restart to evolve (idempotent sink), or choose `rescue`/`schemaHints` deliberately. |
| Hook allowed a destructive op with a warning | Could not verify consumers (no CLI/warehouse) | Advisory — the hook fails open; verify `system.streaming.query_progress` manually before running it. |
## Examples
### Example 1: "About to CREATE OR REPLACE a table other jobs stream from."
The `PreToolUse` hook fires, confirms 2 active consumers via
`system.streaming.query_progress`, and **blocks** with: *"CREATE OR REPLACE mints a
new UUID → both consumers die with DIFFERENT_DELTA_TABLE_READ_BY_STREAMING_SOURCE;
use ALTER / in-place."*
### Example 2: "My MERGE into a Liquid-Clustering table fails with ConcurrentAppendException."
The `merge-rewriter` subagent reads the target's clustering keys via `DESCRIBE
DETAIL` and rewrites the `ON` predicate to include them, so concurrent writers
touch disjoint file sets — the exception stops without serializing the jobs.
### Example 3: "My stream died with DELTA_FILE_NOT_FOUND after a VACUUM."
`recover-streaming-source.py --failure file-not-found --time-travel yes` →
RESTORE_FROM_TIME_TRAVEL (no data loss): restore the source to a pre-VACUUM version,
restart on the existing checkpoint, then align VACUUM retention with the checkpoint lag.
### Example 4: "Before I OPTIMIZE this table."
`pre-optimize-check.sh --table main.sales.orders` reports COLLISION RISK because
`delta.autoOptimize.autoCompact` is on — so the skill recommends letting
auto-compaction do it, or disabling it for the maintenance window first.
## Resources
- [`${CLAUDE_SKILL_DIR}/references/concurrency-conflicts.md`](references/concurrency-conflicts.md) — Delta OCC, auto-compaction collisions (D01), Liquid-Clustering writer conflicts (D02).
- [`${CLAUDE_SKILL_DIR}/references/checkpoint-recovery.md`](references/checkpoint-recovery.md) — the three-tier streaming checkpoint recovery (D03/D04/D12).
- [`${CLAUDE_SKILL_DIR}/references/rocksdb-state-store-tuning.md`](references/rocksdb-state-store-tuning.md) — bounded off-heap state + changelog checkpointing (D05).
- [`${CLAUDE_SKILL_DIR}/references/autoloader-schema-evolution.md`](references/autoloader-schema-evolution.md) — the schema-evolution modes + schemaHints (D10).
- [`${CLAUDE_SKILL_DIR}/references/dlt-rebuild-safety.md`](references/dlt-rebuild-safety.md) — DLT thread race, full-refresh data loss, tier cost (D08/D09/D11).
- [`${CLAUDE_SKILL_DIR}/scripts/pre-optimize-check.sh`](scripts/pre-optimize-check.sh) — auto-compaction collision probe.
- [`${CLAUDE_SKILL_DIR}/scripts/recover-streaming-source.py`](scripts/recover-streaming-source.py) — 4-way recovery decision tree.
- [`${CLAUDE_SKILL_DIR}/hooks/streaming-guard-hook.py`](hooks/streaming-guard-hook.py) — the PreToolUse block for destructive ops on streamed-from tables.
- [`${CLAUDE_SKILL_DIR}/agents/merge-rewriter.md`](agents/merge-rewriter.md) — rewrites a MERGE predicate for Liquid Clustering.
- [Delta concurrency control](https://docs.databricks.com/aws/en/optimizations/isolation-level) · [Structured Streaming production](https://docs.databricks.com/aws/en/structured-streaming/query-recovery) · [Auto Loader schema evolution](https://docs.databricks.com/aws/en/ingestion/cloud-object-storage/auto-loader/schema)
Files in this skill
- SKILL.md
- agents/merge-rewriter.md
- docs/ADR.md
- docs/ONE-PAGER.md
- docs/PRD.md
- eval-spec.yaml
- hooks/streaming-guard-hook.py
- references/autoloader-schema-evolution.md
- references/checkpoint-recovery.md
- references/concurrency-conflicts.md
- references/dlt-rebuild-safety.md
- references/rocksdb-state-store-tuning.md
- scripts/pre-optimize-check.sh
- scripts/recover-streaming-source.py
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.