Skip to content

bug(ingest): unsafe/empty table-name rejections silently drop instead of routing to DLQ #151

Closed

Description

@EricAndrechek

Problem

internal/ingest/bento.go:108:

// Validate table name to prevent SQL injection.
if !safeIdentifierRe.MatchString(raw.TableName) {
    slog.WarnContext(msgCtx, "rejecting message with unsafe table name", "table", raw.TableName)
    // TODO: manually push to a DLQ subject with metadata for later analysis instead of silently dropping?
    if doubleAckErr := m.DoubleAck(msgCtx); doubleAckErr != nil {
        slog.WarnContext(msgCtx, "double ack failed for dropped message", "error", doubleAckErr)
    }
    continue
}

When the table name fails the safeIdentifierRe check, the message is logged at WARN and DoubleAck'd — i.e. permanently removed from JetStream — with no DLQ entry and no payload retained anywhere. Per AGENTS.md design decision #6 the DLQ exists precisely "to prevent silent data loss." This path violates that invariant.

The adjacent empty-table_name branch (bento.go:97-103) has the same shape and the same gap.

Proposed Solution

Route both rejection branches through the existing DLQ output (stream WAVEHOUSE_DLQ, subject dlq.<table> — falling back to dlq.__rejected__ when the table name itself is the reason for rejection). Include the rejection reason in headers (x-wh-drop-reason: unsafe-table-name / empty-table-name) so operators can grep the DLQ for these specifically.

Acceptance criteria

  • No code path in bento.go silently drops a message — every drop either lands in the DLQ or surfaces with full payload at ERROR.
  • Tests cover both the unsafe-table-name and empty-table-name DLQ paths.
  • AGENTS.md design decision ci: bump goreleaser/goreleaser-action from 6 to 7 #6 wording matches the new behavior (or stays as-is if the new behavior matches the stated invariant).

Activity

  1. added
    bugSomething isn't working
    area/ingestIngest pipeline (Bento, batching, DLQ)
    on May 18, 2026
  2. coderabbitai commented on May 18, 2026

    @coderabbitai
    🔗 Related PRs

    #122 - fix(ingest): break infinite-Nak loop on permanent delete errors [merged]
    #124 - chore(api)!: drop hub wildcard fan-out; SSE/WS use ?table= (closes #100) [closed]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. moved this from Backlog to Ready in WaveHouse Task Boardon May 20, 2026
  4. moved this from Ready to In progress in WaveHouse Task Boardon May 21, 2026
  5. EricAndrechek commented on May 21, 2026

    @EricAndrechek
    MemberAuthor

    I think we prefer to handle table name validation at ingest, and assert that as part of the ingest api contract bento will ALWAYS have a table name – so if handled at the API layer they should return errors via the API and fail validation, not making it to the DLQ. Additionally, with the advent of #167, we really should only be rejecting table names that don't exist – and any table name could exist except for an empty string.

  6. moved this from In progress to In review in WaveHouse Task Boardon May 23, 2026
  7. added a commit that references this issue on May 24, 2026
    7f350ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/ingestIngest pipeline (Bento, batching, DLQ)bugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions