> ## Documentation Index
> Fetch the complete documentation index at: https://xata.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# v1.2.5

> pgstream v1.2.5 release notes

**Release Date:** July 28th, 2026

pgstream v1.2.5 is a patch release about data loss that used to be hard to see. The `template`, `json` and `hstore` transformers no longer corrupt their shared random generator under multi-worker snapshots; batches discarded by `ignore_send_errors` are counted and exported as metrics; snapshot failures are logged as errors instead of rendering as `{}`; snapshot request status updates are retried; and a failed restore now carries the output that explains it, with credentials redacted. No migration is required.

## Shared Template State

[PR #1045](https://github.com/xataio/pgstream/pull/1045), by [@kvch](https://github.com/kvch).

The `template`, `json` and `hstore` transformers build their templates from greenmask's toolkit function map, which closes over a single `*rand.Rand` shared by every `random*` and `noise*` function. pgstream builds one transformer per column and calls it from all snapshot workers, so a template as simple as `{{ randomInt 1 1000 }}` had several goroutines drawing from one generator: the lagged-Fibonacci source's indices were corrupted and the call failed with `index out of range [-1]`. With the batch writer's error handling this surfaced as a per-row `DATALOSS` — the transformed value dropped or nulled — rather than a crash, so it was easy to miss.

Templates are now pooled, so each execution gets an instance with function map state of its own. This is the same mechanism applied to the greenmask generators in [PR #884](https://github.com/xataio/pgstream/pull/884), which covered the string transformer and the byte generators but not the template function map. Pooling also covers the other shared state in that map: the `pgtype.Map` behind `tsModify` and `noiseDatePgInterval`.

## Accounting for Dropped Batches

[PR #1042](https://github.com/xataio/pgstream/pull/1042), by [@kvch](https://github.com/kvch).

`ignore_send_errors: true` turns a failed send into a dropped batch and keeps the pipeline running. Until now nothing counted that: each drop produced a log line, with no total anywhere and no metric at all, so the only way to size the loss was to count log lines after the fact.

Every writer that can drop — the Postgres batch and bulk-ingest writers, the Kafka writer and the search indexer — now shares one counter with the batch senders it builds, exported as two observable counters:

* `pgstream.batch.sender.dropped_batches` — batches discarded because `ignore_send_errors` is enabled
* `pgstream.batch.sender.dropped_messages` — messages lost with those batches

Both carry a `writer_type` attribute — `postgres_batch_writer`, `postgres_bulk_ingest_writer`, `kafka_batch_writer` or `search_batch_indexer` — so a run with several writers can be told apart. Each drop is logged with `severity: DATALOSS`, the batch's message count and size, and the running totals; the totals are reported once more at shutdown.

Suppression is also stated at startup rather than being visible only in hindsight: a writer configured with `ignore_send_errors` warns that failing batches will be dropped, and the Postgres batch writer says when `strict_mode` is off, since that governs the per-query drop-and-continue path.

Relatedly, `pgstream.postgres.writer.dropped_queries` is now registered only for the batch writer, the only writer that can increment it. It was previously exported for the bulk-ingest writer as well, where it published a permanent zero under a `writer_type` label naming a component that does drop data, by whole batches.

## Snapshot Reporting

[PR #1039](https://github.com/xataio/pgstream/pull/1039) and [PR #1041](https://github.com/xataio/pgstream/pull/1041), by [@kvch](https://github.com/kvch).

A snapshot that failed logged `snapshot generation completed` at info level with the error rendered as `{}`, because the error was passed as a log field rather than as an error. Failures are now logged as errors with the message `snapshot generation failed`.

Recording the outcome of a snapshot request is also no longer a single attempt: the status update is retried (3 attempts, 500ms apart). If it still cannot be persisted, the failure is logged with `severity: DATALOSS` and the status that remains stored, because a request left in a non-terminal state is never picked up again.

## Restore Errors Carry Their Output

[PR #1040](https://github.com/xataio/pgstream/pull/1040), by [@kvch](https://github.com/kvch).

When `pg_restore` or `psql` exited non-zero without a parseable error, pgstream reported only the exit status, discarding the output that said what actually went wrong. The error now carries the tail of that output (up to 4KiB), with credential material removed first: `PASSWORD '...'` literals in role statements and the row payload psql appends to a failed `COPY` are both redacted.

## Upgrade

No configuration changes are required.

⚠️ **If you use the `template`, `json` or `hstore` transformers with greenmask's `random*`/`noise*` functions**, snapshots run with more than one worker before this release may have written incomplete data: affected values were dropped or nulled per row rather than failing the run. Check the affected columns and re-snapshot if needed. The workaround for earlier versions — sprig's `randInt` in place of `randomInt`, or `table_workers`/`schema_workers` set to 1 — is no longer needed.

**Alerting on drop logs.** When `ignore_send_errors` is enabled, the per-drop line changed from `failed to send batch` to `failed to send batch: dropping it and continuing`, and now carries `severity: DATALOSS`. Alerts keyed on the old message text need updating; keying on the severity field covers this and the other silent-loss sites. The message is unchanged when `ignore_send_errors` is off, where the error still stops the pipeline.

**Metrics.** The two new counters are exported only when instrumentation is enabled. `pgstream.postgres.writer.dropped_queries` no longer appears with `writer_type: postgres_bulk_ingest_writer`; that series was always zero.

**Contributors.** `make lint` now installs golangci-lint v2.10.1 to match CI, which reports findings the previously pinned v2.5.0 did not.

## Support

* Issues: [https://github.com/xataio/pgstream/issues](https://github.com/xataio/pgstream/issues)
* Documentation: [https://github.com/xataio/pgstream/tree/main/docs](https://github.com/xataio/pgstream/tree/main/docs)
* Discussions: [https://github.com/xataio/pgstream/discussions](https://github.com/xataio/pgstream/discussions)
