Pipeline ProblemReport — Codes Catalog
Phase 7 — every transform-path issue (compile error, runtime fallback,
type drift, capability gap, …) flows through the canonical
ProblemReport shape defined in lib/pipelines/problems.ts.
This document is the authoritative join key for the persisted
pipeline_run_problems rows, the /api/pipelines/<id>/problems API
response, the future telemetry dashboard, and any in-product help
links.
Codes are stable. Once a code is emitted to a user, its name is frozen. Renames require a migration that translates old persisted rows. New codes can be added freely (each phase introduces a few).
Reading the entries
| Field | Meaning |
|---|---|
| Code | Stable enum value emitted in ProblemReport.code. |
| Severity | error blocks compile/run; warning surfaces in UI but doesn't block; info is purely informational. |
| Dimension | One of compile / schema / param / type-guard / null-handling / runtime-fallback / drift / dependency. Mirrors the audit rubric. |
| Cause | What user state / data triggers the problem. |
| Fix | Concrete next action for the user. |
| Phase | Which audit phase added the code. |
Generic / fall-through
COMPILE_ERROR — error · compile
- Cause: A compiler threw a non-structured error (anything that isn't already a
ProblemReportError). Catch-all wrapper applied bycompileStack. - Fix: Read the message. Most common: malformed user expression, unknown transform parameter shape, unexpected null in a required field.
- Phase: 1
MISSING_COMPILER — error · compile
- Cause: The widget references a transform name (
widget.type) that has no entry inCOMPILERS. Usually means a deprecated transform or a typo in persisted state. - Fix: Remove the widget, or add the transform's compiler module.
- Phase: 1
Param validation
MISSING_PARAM — error · param
- Cause: A required field is empty or missing from the widget params.
- Fix: Fill in the field.
- Phase: 1
INVALID_PARAM_VALUE — error · param
- Cause: A field's value is the wrong type or out of range (e.g.
Sample: fractionnot in(0, 1]). - Fix: Adjust the value to the allowed range / format.
- Phase: 1
Schema / column references
COLUMN_NOT_FOUND — error · schema
- Cause: A column name in the widget params doesn't exist in the input schema. Usually upstream schema drift (an upstream widget renamed/dropped the column) or a stale param after editing.
- Fix: Pick a different column, or fix the upstream widget so the column survives.
- Phase: 1
OUTPUT_COLLISION — error · schema
- Cause: The widget's output column name collides with an existing column in the input schema.
addColumnStepandreplaceColumnStepboth check. - Fix: Pick a different output name, drop the colliding column upstream, or use a prefix.
- Phase: 3
Type guards
COLUMN_GROUP_MISMATCH — error · type-guard
- Cause: A field declares
acceptsGroups: ['Numeric'](etc.) but the picked column belongs to a different group. Usually a mismatch after schema drift. - Fix: Pick a column of the required group, or apply a Cast first.
- Phase: 1
COLUMN_TYPE_MISMATCH — error · type-guard
- Cause: Stricter than
COLUMN_GROUP_MISMATCH— a field requires specific base types within a group (e.g. Bit shifts needShort / Integer / Long, notDecimal). - Fix: Pick a column of the allowed base type, or Cast first.
- Phase: 2
FN_GROUP_MISMATCH — error · type-guard
- Cause: An aggregation function requires a specific group (e.g.
Sum / Avg / Stddev / Variance / Median / Percentileneed a Numeric column) but the picked column is a different group. Used by Aggregate, Pivot, Rollup, Window. - Fix: Pick a Numeric column, or apply a Cast.
- Phase: 3
TYPE_HOMOGENEITY — error · type-guard
- Cause: A multi-column op (Coalesce, Least, Greatest) was given columns from incompatible type groups. Postgres requires a common type.
- Fix: Apply a Cast to unify the types before the widget.
- Phase: 3
INVALID_LITERAL_CAST — error · param
- Cause: A literal value is not representable as the target base type (e.g.
'abc'cast to Integer inFill nulls). - Fix: Provide a valid literal of the required type.
- Phase: 1
Pattern validation
INVALID_REGEX — error · param
- Cause: The regex pattern in
Replace(regex mode),Match regex, orRegex extractfailed JS regex parsing. POSIX (Postgres) and PCRE (JS) overlap on most patterns; lookaheads and named groups may differ. - Fix: Fix the regex syntax. Test in a JS regex playground first (close approximation).
- Phase: 3
Dependency
MISSING_CAPABILITY — error · dependency
- Cause: The transform requires an optional Postgres extension or a minimum PG version that isn't available in the workspace runtime. Detected via
pg_extensionprobe at boot. - Fix: Install the extension (PostGIS, pgcrypto) or upgrade Postgres (PG14+ for
pg_input_is_valid). The picker UI dims affected transforms when caps are missing. - Phase: 5
Joins (Phase 1 — Pipeline Joins MVP)
Emitted by lib/pipelines/joinSpec.ts → validateJoinSpec and stamped
on the synthetic widget id __join__. The validator runs before the
join compiler; any error here means no SQL is emitted and the
materialise tx is never opened.
JOIN_EMPTY_CONDITIONS — error · param
- Cause: A non-cross join (
inner/left/outer/anti/semi) has zero match conditions. Cross join is the only type allowed to omit the predicate. - Fix: Add at least one match condition (left column = right column), or switch the Join type to
Cross join. - Phase: 1
JOIN_COLUMN_NOT_FOUND — error · schema
- Cause: A column referenced in a match condition or in the output projection no longer exists on its side's schema. Common after a left/right dataset is renamed upstream or its schema drifts.
- Fix: Re-pick the missing column, or rerun the upstream pipeline that produces it.
- Phase: 1
JOIN_TYPE_MISMATCH — error · type-guard
- Cause: Two columns paired in a match condition belong to incompatible
compatGroups (e.g. joining aStringcolumn to aLong). Postgres would either fail at runtime or silently coerce in surprising ways. - Fix: Cast one side to a compatible type before joining (e.g. apply a
Casttransform upstream). - Phase: 1
JOIN_OUTPUT_COLLISION — error · schema
- Cause: Two projected output columns share the same name even after the right prefix is applied. Anti / semi joins skip this check (left-only output).
- Fix: Set or change the right prefix to disambiguate, or deselect one of the two clashing columns.
- Phase: 1
JOIN_CARDINALITY_EXCEEDED — error · runtime-fallback
- Cause: A CROSS join's pre-flight estimate (
|left| × |right|) exceedsPIPELINE_JOIN_MAX_OUTPUT_ROWS(default 10,000,000). Reject path — no rows are materialised. Only fires forjoinType: 'cross'; the other shapes are filter-bounded by their match conditions and don't carry this risk. - Fix: Filter the inputs upstream (a
SampleorFilter rowstransform), or switch to inner / left / outer with a match condition. Workspaces with genuine large-cartesian use cases can raise the cap via the env var. - Phase: 1
JOIN_RESULT_TRUNCATED — warning · runtime-fallback
- Cause: A CROSS join's SQL-level
LIMIT (N+1)backstop clamped the result. Pre-flight passed but the inputs grew between the count estimate and execution (concurrent writes, stale stats). The materialised output is partial — firstJOIN_MAX_OUTPUT_ROWSrows; subsequent rows were not written. - Fix: Re-apply once the inputs stabilise, or filter them upstream to land within the budget. Downstream consumers should treat the output as truncated until the next clean apply.
- Phase: 1
Cross-reference: which transforms emit which codes
| Code | Transforms |
|---|---|
MISSING_COMPILER | (any transform whose compiler is removed) |
MISSING_PARAM | (any transform with required fields) |
INVALID_PARAM_VALUE | Sample, bit shifts, numeric range checks |
COLUMN_NOT_FOUND | (any transform that references columns) |
OUTPUT_COLLISION | All addColumnStep / replaceColumnStep callers (~125 transforms) |
COLUMN_GROUP_MISMATCH | Generic — surfaced via assertColumnGroup |
COLUMN_TYPE_MISMATCH | Bit shift left / Bit shift right |
FN_GROUP_MISMATCH | Aggregate, Pivot, Rollup, Window |
TYPE_HOMOGENEITY | Coalesce, Least, Greatest |
INVALID_LITERAL_CAST | Add constant column, If condition, Map values, Fill nulls |
INVALID_REGEX | Replace (regex mode), Match regex, Regex extract |
MISSING_CAPABILITY | 16 Geo (postgis) + 3 Hash (pgcrypto) + 3 IPv4/IPv6 (pg14) |
JOIN_EMPTY_CONDITIONS | Inner / Left / Outer / Anti / Semi joins (Cross is exempt) |
JOIN_COLUMN_NOT_FOUND | All 6 join types (condition columns + projected columns) |
JOIN_TYPE_MISMATCH | All 6 join types (pairs in match conditions, compatGroup check) |
JOIN_OUTPUT_COLLISION | Inner / Left / Outer / Cross (Anti / Semi return left-only) |
JOIN_CARDINALITY_EXCEEDED | Cross join only (other shapes are filter-bounded) |
JOIN_RESULT_TRUNCATED | Cross join only |
Adding a new code
- Add the literal to
ProblemCodeinlib/pipelines/problems.ts. Order: keep grouped by dimension. - Update the relevant
dimensionenum if a new category emerges. - Add an entry to this document under the right section. Include cause + fix + phase.
- Update the
pipeline_run_problems.dimensionCHECK constraint if a new dimension was added (migration required). - Update the cross-reference table at the bottom.