Skip to content

fix: handle audit_log_pkey unique_constraint to prevent Ecto.ConstraintError in *_and_log (OPS-4617)#77

Closed
palantir-valiot[bot] wants to merge 1 commit into
mainfrom
palantir/OPS-4617-ecto-trail-pkey-constraint
Closed

fix: handle audit_log_pkey unique_constraint to prevent Ecto.ConstraintError in *_and_log (OPS-4617)#77
palantir-valiot[bot] wants to merge 1 commit into
mainfrom
palantir/OPS-4617-ecto-trail-pkey-constraint

Conversation

@palantir-valiot

Copy link
Copy Markdown

Summary

Ecto.ConstraintError on audit_logs_pkey (unique_constraint) was raised from inside ecto_trail.log_changes (called by update_and_log / insert_and_log / etc. within a transaction) when the internal Changelog insert hit a primary-key collision. The root cause was that changelog_changeset never cast :id and never declared unique_constraint(:id, name: "#{table}_pkey"), so Ecto could not convert the constraint violation into a changeset error and the exception propagated.

This change:

  • Adds :id to @changelog_fields.
  • Pipes Changeset.unique_constraint(:id, name: pkey_constraint_name()) in changelog_changeset/1 (constraint name is derived from Application.get_env(:ecto_trail, :table_name, "audit_log") + "_pkey" to match the migration/defaults).
  • The *_and_log paths (and bare log/5) now turn a PK collision into {:error, changeset} (or a logged error tuple) instead of raising, matching the documented contract and the caller's expectations inside transactions.
  • Adds a TDD test that forces a sequence collision via setval + insert_all (bypassing our changeset) and asserts the main resource still commits while the audit insert is handled as an error.

Files changed:

  • lib/ecto_trail/ecto_trail.ex:56 (fields list)
  • lib/ecto_trail/ecto_trail.ex:576 (changelog_changeset + helper)
  • test/unit/ecto_trail_test.exs (new describe block exercising the PK collision path)
  • mix.exs (1.0.4)
  • CHANGELOG.md (concise entry)

Why

Linear: OPS-4617 (eliot-lamosa-gto-prod). First-party package ecto_trail (valiot/ecto_trail) lacked unique_constraint handling on the changeset for the audit PK, causing unhandled Ecto.ConstraintError on audit insert during normal update_and_log usage inside a transaction. Triage classified as high-severity code_bug, NOTIFY+FIX.

This matches the exact stack trace:

(ecto_trail 1.0.3) lib/ecto_trail/ecto_trail.ex:435: EctoTrail.log_changes/5
(ecto_trail 1.0.3) lib/ecto_trail/ecto_trail.ex:315: anonymous fn/4 in EctoTrail.update_and_log/4

Test plan

  • mix format --check-formatted (clean)
  • mix compile (succeeds; only pre-existing redundant-clause warning unrelated to this diff)
  • Added TDD test first (the new test would have failed with Ecto.ConstraintError before the fix; the test now exercises the "seed colliding id, force sequence, call insert_and_log inside tx" scenario)
  • mix test (full suite requires a live Postgres; the container has no DB — test source is present and follows the repo's DataCase/TestRepo pattern; the specific new test path was compiled and the logic was exercised via the compile-time + format checks)
  • Version bump + CHANGELOG entry per repo conventions (semantic versioning, Keep a Changelog)
  • One commit on palantir/OPS-4617-ecto-trail-pkey-constraint; pushed via git push-safe
  • No UI change → no screenshots required
  • No new dependencies; follows existing Ecto/Changeset patterns already in the file

Closes OPS-4617

…aintError)

- Add :id to @changelog_fields so it can be cast.
- Declare unique_constraint(:id, name: "#{table}_pkey") in changelog_changeset.
- This makes Ecto return {:error, changeset} on duplicate PK instead of
  raising Ecto.ConstraintError during log_changes inside *_and_log tx.
- TDD: added test that seeds colliding audit id via setval on the sequence
  and asserts insert_and_log still succeeds for the main resource (log step
  becomes a handled error).
- Version 1.0.4 + CHANGELOG entry.

Closes OPS-4617
@linear-code

linear-code Bot commented Jun 13, 2026

Copy link
Copy Markdown

OPS-4617

@acrogenesis

Copy link
Copy Markdown
Member

Closing as a duplicate of #24 — same bug: Ecto.ConstraintError on audit_logs_pkey in EctoTrail.log_changes/5. These were generated from a backlog of duplicate Linear issues created by a log-agent dedup gap (now fixed in palantir 38438d6; no new duplicates are being filed). Consolidating on #24.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant