Skip to content

fix: add ON DELETE CASCADE to span.trace_id foreign key#12734

Open
Jah-yee wants to merge 1 commit intolangflow-ai:mainfrom
Jah-yee:fix/span-trace-cascade
Open

fix: add ON DELETE CASCADE to span.trace_id foreign key#12734
Jah-yee wants to merge 1 commit intolangflow-ai:mainfrom
Jah-yee:fix/span-trace-cascade

Conversation

@Jah-yee
Copy link
Copy Markdown

@Jah-yee Jah-yee commented Apr 16, 2026

Summary

When deleting a flow, trace rows get deleted (flow_id -> trace ON DELETE CASCADE).
But span.trace_id -> trace.id did NOT have ON DELETE CASCADE,
causing FK violation when trace rows tried to delete:

psycopg.errors.ForeignKeyViolation: update or delete on table "trace" violates foreign key constraint "span_trace_id_fkey" on table "span"

Fix

Added ondelete="CASCADE" to SpanTable.trace_id field:

# Before
trace_id: UUID = Field(foreign_key="trace.id", index=True, ...)

# After
trace_id: UUID = Field(foreign_key="trace.id", ondelete="CASCADE", index=True, ...)

Testing

  1. Start Langflow with PostgreSQL
  2. Create and run a flow (creates tracing data)
  3. Delete the flow from UI
  4. Flow deletion succeeds without FK violation

Closes #12732

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced data integrity by ensuring trace-related records are automatically removed when parent traces are deleted, preventing orphaned data in the system.

When deleting a flow, trace rows get deleted (flow_id -> trace ON DELETE CASCADE).
But span.trace_id -> trace.id did NOT have ON DELETE CASCADE,
causing FK violation when trace rows tried to delete.

Now span.trace_id will cascade delete when parent trace is deleted.

Fixes langflow-ai#12732
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 16, 2026

Walkthrough

Updated the SpanTable.trace_id foreign key definition to include ondelete="CASCADE" parameter. This ensures that when a parent trace record is deleted, all related span records are automatically deleted, preventing foreign key constraint violations in PostgreSQL.

Changes

Cohort / File(s) Summary
Database Schema / Foreign Key Constraint
src/backend/base/langflow/services/database/models/traces/model.py
Added ondelete="CASCADE" to the trace_id foreign key field in SpanTable, enabling automatic deletion of span records when their parent trace is deleted.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error PR adds CASCADE to span.trace_id FK but lacks Alembic migration for existing databases and regression tests for cascade deletion. Create Alembic migration updating span.trace_id FK constraint with ON DELETE CASCADE; add regression tests verifying cascade deletion without FK violations.
Test Quality And Coverage ⚠️ Warning PR lacks adequate test coverage for cascade deletion behavior and missing required database migration file. Add integration test creating flow with trace/span records verifying cascade deletion, and create Alembic migration to update existing databases with ON DELETE CASCADE constraint.
Test File Naming And Structure ❓ Inconclusive PR modifies SpanTable model with CASCADE delete constraint but includes no test files to verify patterns or coverage. Add test files verifying CASCADE behavior, proper foreign key configuration, and cascade deletion across SQLite and PostgreSQL databases following repository test naming conventions.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: add ON DELETE CASCADE to span.trace_id foreign key' directly and clearly summarizes the main change in the changeset.
Linked Issues check ✅ Passed The code change adding ondelete="CASCADE" to SpanTable.trace_id directly addresses the root cause identified in issue #12732, enabling automatic cascade deletion of span rows when trace records are deleted.
Out of Scope Changes check ✅ Passed The change is narrowly scoped to adding ondelete="CASCADE" to the span.trace_id foreign key field, which is entirely within the scope of fixing the cascade deletion issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Excessive Mock Usage Warning ✅ Passed PR modifies only a single model file with a foreign key change; no test files were added, modified, or introduced, making the excessive mock usage check not applicable.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Apr 16, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/backend/base/langflow/services/database/models/traces/model.py`:
- Line 254: Add an Alembic migration to update the existing PostgreSQL foreign
key for span.trace_id to include ON DELETE CASCADE: create a new revision that
in upgrade() drops the current FK constraint on the span.trace_id column and
recreates it with ON DELETE CASCADE, and in downgrade() reverses that by
dropping the CASCADE FK and recreating the original FK without ON DELETE; follow
the same pattern and naming conventions used in migration
0e6138e7a0c2_add_ondelete_cascade_to_file_user_id_fk.py and target the
span.trace_id constraint referenced by the model change (trace_id: UUID Field
with foreign_key="trace.id", ondelete="CASCADE").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: def9b561-f78e-4b2d-a52b-093279648d35

📥 Commits

Reviewing files that changed from the base of the PR and between 9aae6de and 21e7fe2.

📒 Files selected for processing (1)
  • src/backend/base/langflow/services/database/models/traces/model.py


id: UUID = Field(default_factory=uuid4, primary_key=True)
trace_id: UUID = Field(foreign_key="trace.id", index=True, description="Parent trace ID")
trace_id: UUID = Field(foreign_key="trace.id", ondelete="CASCADE", index=True, description="Parent trace ID")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find migrations that touch the span->trace FK behavior
rg -n -C3 'span_trace_id_fkey|span\.trace_id|trace\.id|ON DELETE CASCADE|on delete cascade|create_foreign_key|drop_constraint' \
  src/backend/base/langflow/alembic/versions

# 2) List migration files for manual inspection if needed
fd . src/backend/base/langflow/alembic/versions

Repository: langflow-ai/langflow

Length of output: 30080


🏁 Script executed:

# 1. Check the exact model change at line 254
sed -n '250,260p' src/backend/base/langflow/services/database/models/traces/model.py

# 2. Search more specifically for span.trace_id FK migrations
rg -l 'span' src/backend/base/langflow/alembic/versions/ | xargs grep -l 'trace_id.*ondelete\|ondelete.*trace_id\|span.*trace.*CASCADE'

# 3. Check if there are any migrations specifically mentioning "span" table updates for trace_id
fd . src/backend/base/langflow/alembic/versions/ --exec grep -l 'batch_alter_table.*span' {} \;

Repository: langflow-ai/langflow

Length of output: 528


🏁 Script executed:

# Check the initial span table creation migration to see if CASCADE was already there
cat src/backend/base/langflow/alembic/versions/3478f0bd6ccb_add_trace_and_span_tables.py | head -100

# Also check if there are any subsequent migrations that alter the span table
fd . src/backend/base/langflow/alembic/versions/ --exec grep -l 'batch_alter_table.*"span"' {} \;

Repository: langflow-ai/langflow

Length of output: 4783


🏁 Script executed:

# Check all migrations that alter the span table
cd src/backend/base/langflow/alembic/versions && for file in *.py; do
  if grep -q 'batch_alter_table.*"span"' "$file"; then
    echo "=== $file ==="
    grep -A 10 'batch_alter_table.*"span"' "$file" | head -20
  fi
done

Repository: langflow-ai/langflow

Length of output: 1080


Add an Alembic migration for the span.trace_id FK CASCADE change

The model change at line 254 adds ondelete="CASCADE" to the foreign key definition, but this only affects new database instances. Existing PostgreSQL databases will retain the original constraint without CASCADE until an explicit Alembic migration updates it.

Create a migration that drops and recreates the span.trace_id foreign key constraint with ON DELETE CASCADE, following the pattern used in migration 0e6138e7a0c2_add_ondelete_cascade_to_file_user_id_fk.py.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/backend/base/langflow/services/database/models/traces/model.py` at line
254, Add an Alembic migration to update the existing PostgreSQL foreign key for
span.trace_id to include ON DELETE CASCADE: create a new revision that in
upgrade() drops the current FK constraint on the span.trace_id column and
recreates it with ON DELETE CASCADE, and in downgrade() reverses that by
dropping the CASCADE FK and recreating the original FK without ON DELETE; follow
the same pattern and naming conventions used in migration
0e6138e7a0c2_add_ondelete_cascade_to_file_user_id_fk.py and target the
span.trace_id constraint referenced by the model change (trace_id: UUID Field
with foreign_key="trace.id", ondelete="CASCADE").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deleting a flow with existing trace/span records fails on PostgreSQL because span.trace_id is not ON DELETE CASCADE

1 participant