Diagnose broken or unexplained Databricks compute — slow cold starts, failed cluster launches, Photon paying its premium without the speedup, DBR-upgrade landmines, and spot-interruption shuffle aborts — by correlating a cluster's live event stream across API surfaces. Use when a Databricks cluster won't start, died mid-run, is randomly slow to start, when planning a Databricks Runtime upgrade, or when a job keeps failing on spot loss. Trigger with "databricks cluster won't start", "cluster f...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add jeremylongshore/tons-of-skills-marketplace --skill databricks-cluster-forensics --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Databricks Cluster Forensics?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/jeremylongshore-databricks-cluster-forensics)More formats (shields.io, HTML) on the badges page.
---
name: databricks-cluster-forensics
description: |
Diagnose broken or unexplained Databricks compute — slow cold starts, failed
cluster launches, Photon paying its premium without the speedup, DBR-upgrade
landmines, and spot-interruption shuffle aborts — by correlating a cluster's
live event stream across API surfaces. Use when a Databricks cluster won't
start, died mid-run, is randomly slow to start, when planning a Databricks
Runtime upgrade, or when a job keeps failing on spot loss. Trigger with
"databricks cluster won't start", "cluster failed", "why is my cluster slow",
"NPIP_TUNNEL_SETUP_FAILURE", "databricks runtime upgrade", "photon not helping".
allowed-tools: Read, Write, Edit, Bash(databricks:*), Bash(jq:*), Bash(python3:*), Bash(bash:*), Glob, mcp__databricks-workspace-mcp__clusters_get, mcp__databricks-workspace-mcp__clusters_events, mcp__databricks-workspace-mcp__clusters_list
version: 2.27.0
author: Jeremy Longshore <jeremy@intentsolutions.io>
license: MIT
compatibility: Designed for Claude Code
tags: [saas, databricks, clusters, sre, forensics]
---
# Databricks Cluster Forensics
The operational SRE spine of the pack — what a Databricks engineer reaches for at
2 AM when the compute layer is broken or unexplained. It correlates a cluster's
live event stream across API surfaces to name the failure with its **actual error
code** and its **version-specific mitigation**, not "network problem, try again".
## Overview
Six real compute-layer failures live in this skill; each has a deterministic
detector and an on-demand reference:
1. **Cold-start long-tail** (D01) — on VNet/VPC-injected workspaces a 5-minute
start randomly takes 20-35, and Databricks reports only the aggregate.
`scripts/cluster-coldstart-forensics.py` splits the PENDING window into stages
(provisioning / init-scripts / spark-startup) so you see *which* stage spiked.
2. **Photon premium without the speedup** (D02) — Photon silently falls back to
Spark on UDFs while the cluster still bills the ~2× Photon DBU premium for its
whole uptime. See `references/photon-eligibility-and-fallback.md`.
3. **DBR upgrade landmines** (D03/D04/D05) — 14.x moved the working dir to the
workspace filesystem (a ~500 MB cap that silently breaks large intermediate
writes); 15.1 removed DBFS-root library storage and JDK 11; 15.4 flipped a JDBC
calendar default. `scripts/find-cwd-writes.py` (AST) and `scripts/scan-jar-jdk.sh`
(bytecode target) are the pre-upgrade detectors; `references/dbr-upgrade-paths.md`
is the per-hop encyclopedia.
4. **The launch-failure umbrella** (D06) — `CLOUD_PROVIDER_LAUNCH_FAILURE` /
`NPIP_TUNNEL_SETUP_FAILURE` each hide five distinct causes (subnet IP
exhaustion, DNS, NSG/security-group block, deleted VNet, cloud throttling).
`references/termination-codes.md` disambiguates them.
5. **Spot shuffle aborts** (D10) — a reclaimed spot node forces a shuffle
recompute; lose another mid-recompute and the stage exceeds
`spark.stage.maxConsecutiveAttempts` and the job aborts.
`references/spot-vs-ondemand-decision.md` is the config decision tree.
It is architecturally distinct from the v1 `databricks-common-errors` and
`databricks-incident-runbook` skills: those narrate. This one reads live cluster
events, buckets them deterministically (the arithmetic is in `scripts/`, never
eyeballed), fans out parallel root-cause threads via the `cluster-event-investigator`
subagent, and loads deep knowledge from `references/` only when a symptom needs it.
**Two data planes.** Cluster control-plane evidence (spec, state, event stream)
comes from the custom **`databricks-workspace-mcp`** (`clusters_get` /
`clusters_events` / `clusters_list`). The Photon audit's `system.query.history`
read runs through the **CLI Statement Execution API** (`databricks api post
/api/2.0/sql/statements`) — the same path `databricks-cost-leak-hunter` uses.
Either surface absent, the skill degrades to **advisory mode** and accepts pasted
event JSON / query plans so it still produces value.
## Prerequisites
- **`databricks-workspace-mcp` registered** — the source of `clusters_get`,
`clusters_events`, `clusters_list`. Absent, the skill accepts a pasted
`clusters.events` response and says so (advisory mode).
- **Databricks CLI** authenticated (`databricks auth login`, or the
`DATABRICKS_HOST` + `DATABRICKS_TOKEN` env pair) and `jq` — for the Photon
`system.query.history` read.
- **`DATABRICKS_WAREHOUSE_ID`** set to a running SQL warehouse — required only for
the Photon audit (Step 2); the cold-start / launch-failure flows need only the
workspace MCP.
- **`unzip`** (and ideally a JDK's `javap`) on PATH for the DBR-15.1 JAR scan
(`scan-jar-jdk.sh` falls back to reading class-file bytes if `javap` is absent).
The skill checks which surfaces are present in Step 0 and reports what is missing
before starting a flow it cannot finish.
## Instructions
Pick the flow by symptom. Each is independent; run only what the question needs.
### Step 0: Detect Available Surfaces
Confirm the workspace MCP answers (`clusters_list` returns) and, for a Photon
audit, that the CLI is authenticated and `DATABRICKS_WAREHOUSE_ID` is set. Name
any missing surface and switch that flow to advisory mode (pasted input) rather
than failing mid-diagnosis.
### Step 1: Cold-Start / Launch-Failure Forensics (D01, D06)
Pull the cluster's event stream and bucket its PENDING time:
```bash
# events from the workspace MCP (clusters_events) or the CLI, saved to a file:
databricks clusters events --cluster-id "$CLUSTER_ID" --output json > "$OUT/events.json"
python3 "${CLAUDE_SKILL_DIR}/scripts/cluster-coldstart-forensics.py" \
--input "$OUT/events.json"
```
- If the start **succeeded but was slow**, the dominant stage names the layer:
provisioning → cloud VM allocation or network/DNS/NPIP; init-scripts → a slow
init script or library install; spark-startup → driver spin-up.
- If the start **failed**, read the terminal `termination_reason.code` and
disambiguate with
[`${CLAUDE_SKILL_DIR}/references/termination-codes.md`](references/termination-codes.md)
— especially the `CLOUD_PROVIDER_LAUNCH_FAILURE` / `NPIP_TUNNEL_SETUP_FAILURE`
umbrella and its five sub-causes.
For a messy failure, hand the `cluster_id` to the **`cluster-event-investigator`**
subagent (`/investigate-cluster <id>`): it fans out one thread per cause class and
returns the single most-likely cause with its evidence.
### Step 2: Photon Fallback Audit (D02)
Check whether Photon is earning its premium. Query recent query history for plans
that fell back to Spark, then corroborate the cluster is Photon (`runtime_engine`
via `clusters_get`):
```bash
databricks api post /api/2.0/sql/statements --json "$(jq -n --arg wh "$DATABRICKS_WAREHOUSE_ID" \
'{warehouse_id:$wh, wait_timeout:"30s",
statement:"SELECT statement_id, executed_by, total_duration_ms FROM system.query.history WHERE end_time > now() - INTERVAL 1 DAY ORDER BY total_duration_ms DESC LIMIT 50"}')"
```
Then read the physical plan of the slow statements for the "Photon does not
support" seam and the `ColumnarToRow` / `RowToColumnar` boundaries — the detection
recipe and the UDF-rewrite fixes are in
[`${CLAUDE_SKILL_DIR}/references/photon-eligibility-and-fallback.md`](references/photon-eligibility-and-fallback.md).
### Step 3: DBR Upgrade Readiness (D03, D04, D05)
Before bumping the runtime, run the two pre-upgrade detectors against the job's
code and libraries:
```bash
# D03 — writes to the CWD that the DBR-14 500 MB workspace-FS cap will break:
python3 "${CLAUDE_SKILL_DIR}/scripts/find-cwd-writes.py" --risk-only path/to/job/
# D04 — JARs built for a pre-17 JDK that DBR 15.1's JDK 17 may reject at runtime:
bash "${CLAUDE_SKILL_DIR}/scripts/scan-jar-jdk.sh" path/to/libs/
```
Cross-reference each hop's landmines (the 14.x CWD cap, the 15.1 DBFS-root-library
and JDK-11 removals, the 15.4 JDBC calendar flip) in
[`${CLAUDE_SKILL_DIR}/references/dbr-upgrade-paths.md`](references/dbr-upgrade-paths.md).
### Step 4: Spot Configuration Review (D10)
If a job keeps aborting after `NODES_LOST` / `SPOT_INSTANCE_TERMINATION` around a
shuffle, read the cluster's `aws_attributes` (`clusters_get`) and check the
driver-on-demand rule and the spot ratio against
[`${CLAUDE_SKILL_DIR}/references/spot-vs-ondemand-decision.md`](references/spot-vs-ondemand-decision.md).
The #1 fix is pinning the driver (and a floor of workers) to on-demand so a spot
reclaim can never take the driver.
## Output
- **A cold-start stage breakdown** — total PENDING time split into
provisioning / init-scripts / spark-startup, the dominant stage named, and the
layer to investigate (or, for a failed start, the terminal code + its cause).
- **A root-cause verdict** (from `cluster-event-investigator`) — the single
most-likely cause with the specific events/codes that point to it, and the
cause classes ruled out.
- **A Photon audit** — the queries paying the premium while falling back to Spark,
with the plan seam and the UDF-rewrite fix.
- **A DBR-upgrade risk list** — the CWD writes at risk under the 500 MB cap and
the JARs built for a pre-17 JDK, each with its line/file, plus the per-hop
breaking-change notes.
- **A spot recommendation** — the corrected `aws_attributes` (driver on-demand,
spot ratio) for the job class.
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| `NPIP_TUNNEL_SETUP_FAILURE` / `CLOUD_PROVIDER_LAUNCH_FAILURE` | One of five sub-causes (IP exhaustion, DNS, NSG, deleted VNet, throttling) | Disambiguate via `termination-codes.md`; the fix differs per sub-cause — do not blanket-retry. |
| `clusters_events` empty or truncated | Databricks prunes old events | Note the truncation; a missing `INIT_SCRIPTS_FINISHED` may mean "pruned", not "hung" — do not infer an init-script hang from absence alone. |
| Workspace MCP not registered | Connector not set up | Advisory mode: accept a pasted `clusters.events` JSON and run the forensics script on it. |
| Photon audit returns nothing | No `system.query.history` grant, or `DATABRICKS_WAREHOUSE_ID` unset | Confirm the warehouse id and the `system.query` grant chain; degrade to reading a pasted query plan. |
| `scan-jar-jdk.sh` reports JDK `?` | JAR has no class files, or `unzip` missing | Install `unzip`; a JDK `?` means the JAR is resources-only (no bytecode to check). |
| Cold-start script says "unmeasured" for a stage | The boundary events are absent (no init scripts, or pruned events) | Expected — the script never folds an unmeasured stage into another; investigate the measured stages. |
## Examples
### Example 1: "My cluster randomly takes 25 minutes to start."
Step 1 buckets the events: `provisioning 21m (84%), init-scripts 1m,
spark-startup 3m`. Dominant is provisioning → the skill points at cloud VM
allocation / subnet-IP / DNS, not init scripts, and loads `termination-codes.md`
for the provisioning sub-causes to check.
### Example 2: "Cluster failed with NPIP_TUNNEL_SETUP_FAILURE."
The investigator subagent runs its threads; the network/NPIP thread owns it and
disambiguates to "custom DNS could not resolve the control-plane hostname" (vs the
other four causes), citing the exact check from `termination-codes.md`.
### Example 3: "We're upgrading DBR 13.3 → 15.4. What breaks?"
Step 3 runs `find-cwd-writes.py` (flags 3 `to_parquet("staging/…")` writes at risk
under the 14.x cap) and `scan-jar-jdk.sh` (flags 2 JARs built for JDK 11), and
`dbr-upgrade-paths.md` surfaces the 15.4 JDBC calendar flip for the pipeline's
pre-Gregorian date handling.
### Example 4: "Job keeps dying after losing spot nodes."
Step 4 reads `aws_attributes`, finds the driver is on spot, and recommends
`first_on_demand` covering the driver + a worker floor with `SPOT_WITH_FALLBACK`,
citing the shuffle-recompute cascade in `spot-vs-ondemand-decision.md`.
## Resources
- [`${CLAUDE_SKILL_DIR}/references/termination-codes.md`](references/termination-codes.md) — codebook for every `termination_reason.code`, with the five-cause launch-failure umbrella.
- [`${CLAUDE_SKILL_DIR}/references/dbr-upgrade-paths.md`](references/dbr-upgrade-paths.md) — per-hop DBR breaking changes (14.x CWD cap, 15.1 lib/JDK removals, 15.4 calendar flip).
- [`${CLAUDE_SKILL_DIR}/references/photon-eligibility-and-fallback.md`](references/photon-eligibility-and-fallback.md) — what drops Photon to Spark and how to detect the premium-without-speedup.
- [`${CLAUDE_SKILL_DIR}/references/spot-vs-ondemand-decision.md`](references/spot-vs-ondemand-decision.md) — the spot config decision tree + driver-on-demand rule.
- [`${CLAUDE_SKILL_DIR}/scripts/cluster-coldstart-forensics.py`](scripts/cluster-coldstart-forensics.py) — buckets cold-start PENDING time by stage.
- [`${CLAUDE_SKILL_DIR}/scripts/find-cwd-writes.py`](scripts/find-cwd-writes.py) — AST scanner for DBR-14 CWD writes.
- [`${CLAUDE_SKILL_DIR}/scripts/scan-jar-jdk.sh`](scripts/scan-jar-jdk.sh) — JAR bytecode-target (JDK) scanner.
- [`${CLAUDE_SKILL_DIR}/agents/cluster-event-investigator.md`](agents/cluster-event-investigator.md) — parallel root-cause fanout subagent.
- [Databricks cluster events API](https://docs.databricks.com/api/workspace/clusters/events) · [Databricks Runtime release notes](https://docs.databricks.com/aws/en/release-notes/runtime/) · [Photon](https://docs.databricks.com/aws/en/compute/photon)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!