Compiler ErrorsProjections

Projections

Errors from the projections: block — shard keys, lookups, resolvers, partitioning, and the runtime contract projections must satisfy.

42 error codes in this section.

Projection Shard

VERR_PROJECTION_SHARD_INVALID_LOCATION

shard() used in invalid location. shard() is used inside an aggregate expression, query, or any context outside derive:.

Impact: DDL or query plan generation fails; projection cannot deploy.

✗ Won't compile
aggregates:
  CheckedIn:
    checkin_count:
      op: add
      by: "shard(4, event.payload.venue_id)"   # invalid here
✓ Fixed
derive:
  venue_shard: "shard(4, event.payload.venue_id)"
aggregates:
  CheckedIn:
    checkin_count:
      op: add
      by: "derive:venue_shard"

VERR_PROJECTION_SHARD_INVALID_COUNT

shard() count is invalid. The shard count argument is zero, negative, or exceeds the plan’s maximum.

Impact: Projection cannot be compiled or deployed.

✗ Won't compile
derive:
  venue_shard: "shard(0, event.payload.venue_id)"   # 0 is invalid
✓ Fixed
derive:
  venue_shard: "shard(8, event.payload.venue_id)"   # 1–32

VERR_PROJECTION_SHARD_NON_DETERMINISTIC

shard() expression is non-deterministic. The shard expression argument uses now() or random() instead of a stable event-scoped value.

Impact: Same event shards to a different bucket on replay; projection rows are scattered incorrectly.

✗ Won't compile
derive:
  shard: "shard(8, now())"   # non-deterministic
✓ Fixed
derive:
  shard: "shard(8, event.entity_id)"   # stable

Projection Lookup Safety

VERR_PROJECTION_LOOKUP_AGGREGATION_VIOLATION

lookup() inside aggregate expression. A lookup() call is used inside an aggregate by: expression.

Impact: Projection compilation fails.

✗ Won't compile
aggregates:
  CheckedIn:
    venue_total:
      op: add
      by: "lookup(venue, event.payload.venue_id).weight"
✓ Fixed
derive:
  venue_weight: "lookup(venue, event.payload.venue_id).weight"
aggregates:
  CheckedIn:
    venue_total:
      op: add
      by: "derive:venue_weight"

VERR_PROJECTION_LOOKUP_BUCKET_VIOLATION

lookup() in bucket expression. A lookup() call is used inside a bucket.field expression.

Impact: Projection compilation fails.

✗ Won't compile
bucket:
  field: "lookup(venue, id).opened_at"   # invalid
✓ Fixed
# Bucket fields must be event-scoped.
bucket:
  field: event.ts

VERR_PROJECTION_LOOKUP_DYNAMIC_VIOLATION

lookup() with dynamic identity expression. The lookup ID argument uses a computed or aggregated value rather than a raw event-scope path.

Impact: Projection may load the wrong entity for some events.

✗ Won't compile
derive:
  name: "lookup(venue, shard_id + offset).name"   # computed ID
✓ Fixed
derive:
  name: "lookup(venue, event.payload.venue_id).name"   # raw event path

VERR_PROJECTION_LOOKUP_NESTED_VIOLATION

Nested lookup() call. A lookup() call is nested inside another lookup() call.

Impact: Projection compilation fails.

✗ Won't compile
derive:
  name: "lookup(venue, lookup(event, id).venue_id).name"
✓ Fixed
# Use a resolver block to chain lookups:
resolver:
  event_entity:
    entity: event
    key: event.entity_id

VERR_PROJECTION_LOOKUP_LIMIT_EXCEEDED

Too many lookup() calls. The projection exceeds the plan-permitted maximum number of lookup() calls.

Impact: Projection is rejected by the tier validator.

✗ Won't compile
# 5 lookup() calls on a plan that allows max 3
✓ Fixed
# Reduce lookup count, or upgrade to a higher plan tier.

VERR_PROJECTION_LOOKUP_FANOUT_VIOLATION

lookup() resolves to multiple entities. A lookup() call uses a relationship/collection field as the identity argument, which could resolve to multiple entities.

Impact: Projection produces wrong or duplicated rows.

✗ Won't compile
derive:
  name: "lookup(venue, event.payload.venue_ids).name"   # plural — fan-out
✓ Fixed
# lookup() must resolve to exactly one entity.
# Use the resolver block for relationship traversal.

VERR_PROJECTION_COMPLEXITY_EXCEEDED

Projection exceeds complexity threshold. The combination of derive fields, aggregates, lookups, and mutations pushes the projection past the complexity limit.

Impact: Projection is rejected; no DDL is generated.

✗ Won't compile
# Very wide projection with 20 derive fields, 5 lookups, and complex mutations
✓ Fixed
# Split the projection into two or more narrower projections.

VERR_PROJECTION_COST_TOO_HIGH

Projection estimated CU cost too high. The projection’s estimated compute-unit cost exceeds the plan maximum.

Impact: Projection is rejected by the tier validator.

✗ Won't compile
# Very wide projection with high shard count and many join lookups
✓ Fixed
# Reduce lookup count, shard count, or derive complexity.
# Consider splitting into multiple projections.

VERR_PROJECTION_TIER_VIOLATION

Projection exceeds plan tier limits. The projection exceeds a plan-tier limit: lookup count, shard count, bucket interval, or complexity score.

Impact: Projection cannot be deployed on the current plan.

✗ Won't compile
# 3 lookups on Starter tier that allows max 1
✓ Fixed
# Reduce usage to match your plan tier, or upgrade.

Projection Resolver

VERR_PROJECTION_RESOLVER_ENTITY_NOT_FOUND

Resolver entity does not exist. A resolver’s entity: field references a state name that is not defined in the spec.

Impact: Resolver loads null for every event; all derive fields using this resolver produce null.

✗ Won't compile
resolver:
  venue:
    entity: venue   # 'venue' not in state:
    key: event.payload.venue_id
✓ Fixed
state:
  venue: { ... }
# then add the resolver

VERR_PROJECTION_RESOLVER_KEY_NOT_FOUND

Resolver key field missing. A resolver definition is missing the required key: field.

Impact: Resolver cannot identify which entity to load; loads null for every event.

✗ Won't compile
resolver:
  venue:
    entity: venue   # key is missing
✓ Fixed
resolver:
  venue:
    entity: venue
    key: event.payload.venue_id

VERR_PROJECTION_RESOLVER_KEY_INVALID

Resolver key is not event-scoped. A resolver key: is not a valid event-scoped expression (must start with event.payload.* or event.*). An invalid key silently resolves to null for every event, loading the wrong entity.

Impact: Resolver loads the wrong entity for every event; all related derive fields are incorrect.

✗ Won't compile
resolver:
  venue:
    entity: venue
    key: venue_id            # not event-scoped
✓ Fixed
resolver:
  venue:
    entity: venue
    key: event.payload.venue_id

VERR_PROJECTION_RESOLVER_DUPLICATE_ALIAS

Duplicate resolver alias. The same alias name is defined twice in the resolver block of a single projection.

Impact: Second definition silently overrides the first; resolver behaviour is unpredictable.

✗ Won't compile
resolver:
  venue: { entity: venue, key: event.payload.venue_id }
  venue: { entity: place, key: event.payload.place_id }   # duplicate
✓ Fixed
# Use unique alias names: 'venue' and 'place'

VERR_PROJECTION_RESOLVER_RESERVED_ALIAS

Resolver alias uses reserved name. A resolver alias shadows the reserved names event or state.

Impact: All derive expressions using event.* or state.* may resolve against the resolver instead.

✗ Won't compile
resolver:
  event:                  # reserved name
    entity: venue
    key: event.payload.venue_id
✓ Fixed
resolver:
  venue:
    entity: venue
    key: event.payload.venue_id

VERR_PROJECTION_RESOLVER_UNDEFINED_ALIAS

Derive references undefined resolver alias. A derive expression references a resolver alias that is not declared in the resolver block.

Impact: Derive field resolves to null for every event.

✗ Won't compile
# No 'venue' alias in resolver:
derive:
  venue_name: "venue.name"   # undefined alias
✓ Fixed
resolver:
  venue:
    entity: venue
    key: event.payload.venue_id
derive:
  venue_name: "venue.name"

VERR_PROJECTION_RESOLVER_INVALID_PATH

Resolver alias path does not exist on target state. A derive expression uses a resolver alias path that does not exist on the target entity’s state schema.

Impact: Derive field produces null for every event; no SQL error but data is silently wrong.

✗ Won't compile
# venue state has no 'postal_code' field
derive:
  venue_zip: "venue.postal_code"   # field doesn't exist
✓ Fixed
# Use a field that exists in the venue state schema:
derive:
  venue_zip: "venue.address.zip"

VERR_PROJECTION_RESOLVER_CIRCULAR

Resolver key references another resolver alias. A resolver’s key: references another resolver alias instead of an event-scope path, creating a chain or cycle.

Impact: Resolver cannot evaluate; projection fails for every event.

✗ Won't compile
resolver:
  venue:
    entity: venue
    key: place.id        # references 'place' alias
  place:
    entity: place
    key: event.payload.place_id
✓ Fixed
resolver:
  venue:
    entity: venue
    key: event.payload.venue_id   # direct event-scope reference
  place:
    entity: place
    key: event.payload.place_id

Projection Partitioning

VERR_PROJECTION_PARTITION_INVALID_STRATEGY

Invalid partition strategy. partition.strategy is missing or not one of: range, hash, list.

Impact: Projection DDL cannot be generated; deployment fails.

✗ Won't compile
partition:
  strategy: sharded   # invalid
✓ Fixed
partition:
  strategy: range   # range | hash | list

VERR_PROJECTION_PARTITION_FIELD_MISSING

Partition field missing or undeclared. partition.field is missing or references a column that is not declared on the projection.

Impact: Deployment fails; table cannot be created.

✗ Won't compile
partition:
  strategy: range
  field: created_at   # not in projection fields
✓ Fixed
# Add 'created_at' to fields: or derive: first,
# then reference it in partition.field.

VERR_PROJECTION_PARTITION_FIELD_NOT_IN_PK

Partition field not in primary key. Postgres requires all partition key columns to be part of the primary key.

Impact: DDL creation fails with a Postgres error at deploy time.

✗ Won't compile
target:
  primary_key: [checkin_id]
partition:
  field: created_at   # not in primary_key
✓ Fixed
target:
  primary_key: [checkin_id, created_at]
partition:
  field: created_at

VERR_PROJECTION_PARTITION_INVALID_FIELD_TYPE

Partition field type incompatible with strategy. The partition field type is not supported by the chosen strategy (e.g. GEOGRAPHY_POINT on range).

Impact: Deployment fails with a Postgres DDL error.

✗ Won't compile
fields:
  location: GEOGRAPHY_POINT
partition:
  strategy: range
  field: location   # geo type incompatible with range
✓ Fixed
# Use TIMESTAMP/TIMESTAMPTZ for range, UUID/TEXT/INT for hash or list.

VERR_PROJECTION_PARTITION_RANGE_INTERVAL_REQUIRED

Range partition missing interval. A range partition on a temporal field is missing the required interval configuration.

Impact: Deployment fails; Postgres cannot create child partitions.

✗ Won't compile
partition:
  strategy: range
  field: created_at
  # interval is missing
✓ Fixed
partition:
  strategy: range
  field: created_at
  interval: "1 month"

VERR_PROJECTION_PARTITION_HASH_COUNT_REQUIRED

Hash partition missing partitions count. A hash partition is missing the required partitions count.

Impact: Deployment fails; Postgres cannot create hash partition buckets.

✗ Won't compile
partition:
  strategy: hash
  field: user_id
  # partitions count is missing
✓ Fixed
partition:
  strategy: hash
  field: user_id
  partitions: 8

VERR_PROJECTION_PARTITION_RANGE_INTERVAL_INVALID

Range partition interval has invalid format. The range partition interval value does not match the recognised format: N day|week|month|year.

Impact: Deployment fails; Postgres rejects the interval string.

✗ Won't compile
partition:
  interval: "monthly"   # invalid format
✓ Fixed
partition:
  interval: "1 month"   # N day|week|month|year

VERR_PROJECTION_PARTITION_RANGE_PRECREATE_NEGATIVE

Range partition precreate is negative. The partition.precreate value is a negative integer.

Impact: Compilation fails; no partitions are created.

✗ Won't compile
partition:
  precreate: -1
✓ Fixed
partition:
  precreate: 3   # create 3 future partitions

VERR_PROJECTION_PARTITION_HASH_COUNT_TOO_HIGH

Hash partition count exceeds maximum. partition.partitions exceeds the plan-permitted maximum bucket count.

Impact: Projection is rejected by the tier validator.

✗ Won't compile
partition:
  partitions: 512   # exceeds plan maximum
✓ Fixed
# Reduce partition count to within the plan maximum (typically 32 or 64).

VERR_PROJECTION_PARTITION_STRAY_FIELD

Partition config has field for wrong strategy. A partition config field belongs to a different strategy (e.g. interval on a hash partition).

Impact: Compilation fails with a stray-field error.

✗ Won't compile
partition:
  strategy: hash
  partitions: 8
  interval: "1 month"   # interval is only for range
✓ Fixed
partition:
  strategy: hash
  field: user_id
  partitions: 8

VERR_PROJECTION_PARTITION_KEY_UPDATE_CONFLICT

bulk_update sets partition key column. A bulk_update mutation includes the partition key column in its set: block. Postgres forbids updating partition keys on partitioned tables.

Impact: bulk_update throws a Postgres error at runtime for every matching event.

✗ Won't compile
mutations:
  UserUpdated:
    op: bulk_update
    set:
      user_id: event.payload.user_id   # user_id is the partition field
✓ Fixed
# Remove the partition key from set:.
# To change partition key, delete and re-insert the row.

VERR_PROJECTION_PARTITION_TABLE_CONFLICT

Multiple projections have conflicting partition configs for same table. Two projections targeting the same table declare different partition configurations.

Impact: Deployment fails; Postgres cannot apply conflicting partition DDL.

✗ Won't compile
# projection_a: strategy: range on created_at
# projection_b: strategy: hash on user_id (same table)
✓ Fixed
# All projections targeting the same table must declare identical partition configs.

Projection Runtime-Contract

VERR_PROJECTION_DUPLICATE_TABLE_PK_CONFLICT

Conflicting primary keys on shared table (legacy code). Two projections target the same physical table but declare different primary_key lists. See VERR_PROJECTION_TABLE_PRIMARY_KEY_CONFLICT for the canonical code.

Impact: DDL for the second projection collides with the first’s PK constraint at deploy time.

✗ Won't compile
# projections A and B share a table but have different primary_key lists
✓ Fixed
# All projections targeting the same table must declare identical primary keys.

VERR_PROJECTION_TABLE_PRIMARY_KEY_CONFLICT

Conflicting primary keys on shared table. Two projections target the same physical table but declare conflicting primary_key lists. DDL collision — deploy will fail or silently truncate existing rows.

Impact: Deployment fails with a constraint violation, or one projection’s PK is silently ignored.

✗ Won't compile
projections:
  daily_checkins:
    target:
      table: checkin_totals
      primary_key: [venue_id, date]
  venue_totals:
    target:
      table: checkin_totals
      primary_key: [venue_id]   # conflict!
✓ Fixed
# All projections sharing 'checkin_totals' must agree on the same primary_key.

VERR_PROJECTION_AGGREGATE_FIELD_MISSING_TYPE

Aggregate target field has no declared type. An aggregate target field used by add/sub/set has no entry in fields:. The DDL generator defaults to BIGINT, silently breaking set operations that write non-integer values.

Impact: DOUBLE/TEXT values stored as aggregates are silently truncated or fail at runtime.

✗ Won't compile
# No fields.average_score declaration
aggregates:
  RatingSubmitted:
    average_score:
      op: set
      by: event.payload.score
✓ Fixed
fields:
  average_score: DOUBLE   # declare the type
aggregates:
  RatingSubmitted:
    average_score:
      op: set
      by: event.payload.score

VERR_PROJECTION_LOOKUP_FIELD_PATH_MISSING_STATE

lookup() path missing in state schema (legacy code). A lookup(stream, expr).fieldPath references a path that does not exist on the resolved stream’s state schema. See VERR_PROJECTION_LOOKUP_FIELD_NOT_FOUND for the canonical code.

Impact: Derive field silently produces null for every event.

✗ Won't compile
derive:
  zip: "lookup(venue, event.payload.venue_id).postal_code"
  # venue has no postal_code
✓ Fixed
derive:
  zip: "lookup(venue, event.payload.venue_id).address.zip"

VERR_PROJECTION_LOOKUP_FIELD_NOT_FOUND

lookup() or resolver path not found in target state. A lookup(stream, expr).fieldPath expression or resolver alias path references a field that does not exist on the target state schema. The worker silently produces null for every event.

Impact: Projection columns are all null; no SQL error but data is silently wrong.

✗ Won't compile
derive:
  venue_zip: "lookup(venue, event.payload.venue_id).postal_code"
  # 'postal_code' not in venue state
✓ Fixed
derive:
  venue_zip: "lookup(venue, event.payload.venue_id).address.zip"   # correct path

VERR_PROJECTION_AGGREGATE_DERIVE_FIELD_MISSING

Aggregate by: derive:x references undeclared derive field. An aggregate by: derive:x references a derive field x that is not declared in the projection’s derive: block. The worker defaults by to 1, silently corrupting counter increments.

Impact: All increments use 1 instead of the intended delta value; counters are incorrect.

✗ Won't compile
# score_delta NOT in derive:
aggregates:
  RatingSubmitted:
    rating_total:
      op: add
      by: "derive:score_delta"   # missing derive field
✓ Fixed
derive:
  score_delta: "event.payload.score_delta"
aggregates:
  RatingSubmitted:
    rating_total:
      op: add
      by: "derive:score_delta"

VERR_PROJECTION_AGGREGATE_EVENT_FIELD_INVALID

Aggregate by: event path is malformed. An aggregate by: event.payload.foo or by: event.foo is not a well-formed event-scope expression. The worker silently substitutes 0, producing incorrect counter values.

Impact: All aggregate increments use 0; counters are silently zeroed.

✗ Won't compile
aggregates:
  RatingSubmitted:
    rating_total:
      op: add
      by: "payload.score"   # missing 'event.' prefix
✓ Fixed
aggregates:
  RatingSubmitted:
    rating_total:
      op: add
      by: "event.payload.score"

VERR_PROJECTION_INDEX_COLUMN_MISSING

Index column not found on projection. An explicit indexes: entry references a column not declared in fields:, derive:, primary_key, or bucket_start. The DDL generator silently skips or errors on the index.

Impact: Index is not created; queries that rely on it perform full table scans.

✗ Won't compile
fields:
  venue_id: TEXT
indexes:
  - columns: [venue_id, created_at]   # created_at undeclared
✓ Fixed
fields:
  venue_id: TEXT
  created_at: TIMESTAMPTZ   # add the field
indexes:
  - columns: [venue_id, created_at]

VERR_PROJECTION_INDEX_TYPE_MISMATCH

Index type incompatible with field type. An explicit index type is incompatible with the declared field type. GIST requires GEOGRAPHY_POINT/GEOGRAPHY; GIN requires TEXT/STRING.

Impact: Deployment fails with a Postgres DDL error.

✗ Won't compile
fields:
  venue_id: TEXT
indexes:
  - columns: [venue_id]
    type: GIST   # GIST only valid on GEOGRAPHY_POINT
✓ Fixed
fields:
  location: GEOGRAPHY_POINT
indexes:
  - columns: [location]
    type: GIST

VERR_PROJECTION_FIELD_TYPE_UNKNOWN

Unknown field type. A projection declares a field with a type string the compiler does not recognise. The DDL generator silently falls back to TEXT, hiding schema intent and causing type-mismatch bugs.

Impact: Aggregates on numeric fields may fail or produce wrong results due to TEXT default.

✗ Won't compile
fields:
  score: float64          # not recognised
  created_at: datetime    # not recognised
✓ Fixed
fields:
  score: DOUBLE
  created_at: TIMESTAMPTZ
# Supported: TEXT STRING VARCHAR INT INTEGER BIGINT SMALLINT
#            DOUBLE FLOAT NUMERIC DECIMAL BOOLEAN BOOL
#            TIMESTAMP TIMESTAMPTZ DATE UUID
#            GEOGRAPHY_POINT GEOGRAPHY JSONB JSON