Skip to content

Conversation

@pyramation
Copy link
Contributor

@pyramation pyramation commented Jan 1, 2026

feat: improve PostgreSQL error messages with extended fields

Summary

Adds comprehensive PostgreSQL error formatting utilities that surface extended error fields (detail, hint, where, position, schema, table, column, constraint, etc.) for better debugging. These fields are available from pg-protocol but were previously not surfaced in error messages.

Changes:

  • New shared utility in @pgpmjs/types with extractPgErrorFields, formatPgErrorFields, and formatPgError functions
  • Enhanced error logging in pgpm/core migration utilities (transaction.ts, client.ts)
  • Enhanced errors in PgTestClient enabled by default (can be disabled via enhancedErrors: false)
  • Improved seed error handling in pgsql-test
  • Fixed pgpm_migrate stored procedures to preserve PostgreSQL error diagnostics using GET STACKED DIAGNOSTICS
  • Enhanced thrown errors from PgpmMigrate.deploy() and revert() with extended fields
  • Comprehensive tests using real database connections (no mocks)
  • Jest snapshots showing exact formatted error output from real PostgreSQL errors

Example enhanced error output for JSON/JSONB type mismatch:

invalid input syntax for type json
Detail: Token "not_valid_json" is invalid.
Where: JSON data, line 1: not_valid_json
Query: INSERT INTO test_json_errors (name, config) VALUES ($1, $2)
Values: ["test_name","not_valid_json"]

Example nested EXECUTE migration error (captures full PL/pgSQL call stack):

relation "nonexistent_migration_table" does not exist
Where: PL/pgSQL function inline_code_block line 3 at EXECUTE
       SQL statement "DO $$ BEGIN EXECUTE '...' END; $$;"
       PL/pgSQL function pgpm_migrate.deploy(...) line 46 at EXECUTE
Internal Query: INSERT INTO nonexistent_migration_table (col) VALUES (1)

Updates since last revision

  • Fixed stored procedures to preserve error diagnostics - Modified pgpm_migrate.deploy and pgpm_migrate.revert in procedures.sql to use GET STACKED DIAGNOSTICS to capture all error fields (sqlstate, message, detail, hint, context, schema, table, column, constraint, datatype) and re-raise with RAISE EXCEPTION USING to preserve them
  • Enhanced thrown errors from PgpmMigrate - deploy() and revert() now call formatPgError() on caught errors before re-throwing, with a __pgpmEnhanced guard flag to prevent double-formatting
  • Migration error snapshots now show enhanced fields - The snapshots now display actual PostgreSQL error fields (code, detail, where, schema, table, constraint, internalQuery) instead of undefined

Review & Testing Checklist for Human

  • Review SQL stored procedure changes - Check pgpm/core/src/migrate/sql/procedures.sql - the GET STACKED DIAGNOSTICS and RAISE EXCEPTION USING pattern is used to preserve error context. Verify this is compatible with your PostgreSQL version (tested on PG 13, should work on PG 9.1+)
  • Review error mutation approach - client.ts mutates error.message directly and adds __pgpmEnhanced flag. This preserves instanceof but modifies the original error object
  • Verify migration error snapshots - Check postgres-test.pgpm-migration-errors.test.ts.snap - errors should now show code, detail, where, schema, table, constraint fields populated
  • Check params logging change - transaction.ts now logs full params instead of truncating to 3 items. Verify this is acceptable for your use case (could expose sensitive data in logs)

Recommended test plan:

  1. Run the full test suite in CI and verify all existing tests pass
  2. Manually trigger a migration error (e.g., reference a nonexistent table) and verify the thrown error includes extended fields like where, detail, schema, table
  3. Verify the where field shows the full PL/pgSQL call stack through pgpm_migrate.deploy

Notes

  • User explicitly requested no truncation of sensitive data and no special JSON hints
  • Enhanced errors are now enabled by default for better debugging experience
  • Tests use real database connections and actual PostgreSQL errors (requires PostgreSQL in CI)
  • The GET STACKED DIAGNOSTICS approach is version-independent (PG 9.1+) - the root cause was PL/pgSQL catching/rethrowing around EXECUTE which discards extended fields unless explicitly captured

Link to Devin run: https://app.devin.ai/sessions/6a6a51e6869745d390b2f36f18ebfdb8
Requested by: Dan Lynch (@pyramation)

- Add shared pg-error-format utility in @pgpmjs/types with extractPgErrorFields,
  formatPgErrorFields, and formatPgError functions
- Enhance pgpm/core migrate/utils/transaction.ts with extended PG error fields
- Enhance pgpm/core migrate/client.ts with extended PG error fields
- Add opt-in enhanced errors to PgTestClient via enhancedErrors option or
  PGSQL_TEST_ENHANCED_ERRORS env var
- Improve seed error handling in pgsql-test connect.ts
- Add comprehensive tests for error formatting utilities

This provides better debugging information for PostgreSQL errors including:
- detail, hint, where, position fields
- schema, table, column, dataType, constraint fields
- query and values context when available
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Enhanced PostgreSQL error messages are now enabled by default for better
debugging experience. Can be disabled via enhancedErrors: false option or
PGSQL_TEST_ENHANCED_ERRORS=0 environment variable.
- Remove PGSQL_TEST_ENHANCED_ERRORS env var check (enhanced errors now
  always default to true, can be disabled via enhancedErrors: false option)
- Add tests for nested EXECUTE migration errors with full call stack context
- Add tests for constraint violations in nested EXECUTE
- Add tests for transaction aborted errors with context
Add Jest snapshots showing the exact formatted output for:
1. JSON/JSONB type mismatch error (simple case)
2. Nested EXECUTE migration error with full PL/pgSQL call stack
Remove all mock error objects and replace with real database tests that:
- Create actual tables with constraints
- Trigger real PostgreSQL errors (JSON type mismatch, unique violations, FK violations, etc.)
- Use getConnections() and PgTestClient for proper test isolation
- Include snapshot tests for error message formatting

Tests will generate snapshots in CI where PostgreSQL is available.
Snapshots generated from actual PostgreSQL errors in CI:
1. JSON/JSONB type mismatch error
2. Unique constraint violation error
3. Foreign key violation error
4. Undefined table error
5. Nested EXECUTE error with PL/pgSQL call stack
6. Constraint violation inside nested EXECUTE
…cedures

Use GET STACKED DIAGNOSTICS to capture all error fields (sqlstate, message,
detail, hint, context, schema, table, column, constraint, datatype) when
EXECUTE fails, and re-raise with RAISE EXCEPTION USING to preserve them.

This ensures the Node.js pg library receives the full error context, which
can then be formatted by formatPgError for enhanced error messages.
The GET STACKED DIAGNOSTICS fix now preserves PostgreSQL error context:
- code: error codes like 42P01, 23505, 22P02
- detail: constraint violation details
- schema/table/constraint: object identifiers
- where: full PL/pgSQL call stack
- internalQuery: the actual failing SQL statement
@pyramation pyramation merged commit efb43ec into main Jan 2, 2026
36 checks passed
@pyramation pyramation deleted the devin/1767310270-improve-pg-error-messages branch January 2, 2026 04:55
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.

2 participants