When Replicat abends, the error message tells you what failed, but rarely why. INFO REPLICAT and the report file point you at a table and an error code — to actually understand the data that caused it, you need to open the trail file itself with Logdump, GoldenGate’s trail-file inspection utility. This post walks through a real investigation end to end, from the initial abend to the actual root cause sitting inside the raw record bytes.
1. The Symptom
Replicat REP1 abends applying to a target order-management schema. GGSCI shows it stopped, not running:
GGSCI> INFO REPLICAT REP1
REPLICAT REP1 Last Started 2026-07-09 08:14 Status ABENDED
Checkpoint Lag 00:00:00 (updated 00:02:11 ago)
Log Read Checkpoint File ./dirdat/rt000412
2026-07-09 08:41:07.311402 RBA 88213402
The report file (dirrpt/REP1.rpt) has the actual error:
2026-07-09 08:41:07 ERROR OGG-01296 Error mapping from ORDERS.ORDER_NOTES to
TARGET.ORDER_NOTES.
2026-07-09 08:41:07 ERROR OGG-01161 Bad column index (3), table ORDERS.ORDER_NOTES,
db operation: insert. Encountered an ORA-12899.
2026-07-09 08:41:07 ERROR OGG-01296 ORA-12899: value too large for column
"TARGET"."ORDER_NOTES"."NOTES" (actual: 512, maximum: 500)
ORA-12899 on a column that’s supposedly VARCHAR2(500) — but the source column is also defined as 500 characters, and this row passed validation on insert at the source. Something is changing size in transit.
2. First Stop: the Discard File
Before touching Logdump, check the discard file GoldenGate writes when a record fails to apply — it often has enough context on its own:
cat dirrpt/REP1.dsc
***********************************************************************
Discarded record from action ABEND on error 12899
Aborting transaction on ...
Problem replicating ORDERS.ORDER_NOTES to TARGET.ORDER_NOTES
Error ORA-12899: value too large for column "TARGET"."ORDER_NOTES"."NOTES"
(actual: 512, maximum: 500)
Trail file: ./dirdat/rt000412
Record position (RBA): 88213402
That gives us exactly what we need to pull the actual record out of the trail file: the trail file name and the RBA (relative byte address) of the failing record.
3. Opening the Trail File in Logdump
Logdump ships alongside GGSCI in $GG_HOME:
$GG_HOME/logdump
Logdump 55 >
Point it at the trail file and turn on header and detail views so records print in a readable form instead of raw hex:
Logdump 1 > OPEN ./dirdat/rt000412
Current LogTrail is ./dirdat/rt000412
Logdump 2 > GHDR ON
Logdump 3 > DETAIL DATA
Logdump 4 > USETOKEN ON
Logdump 5 > FILTER TABLE ORDERS.ORDER_NOTES
Logdump 6 > POS 88213402
Reading forward from RBA 88213402
Logdump 7 > NEXT
4. Reading the Record
NEXT prints the record at that position:
___________________________________________________________________
Hdr-Ind : E (x45) Partition : . (x04)
UndoFlag : . (x00) BeforeAfter: A (x41)
RecLength : 512 (x0200) IO Time : 2026/07/09 08:41:06.998.421
IOType : 115 (x73) OrigNode : 255 (xff)
TransInd : . (x03) FormatType : R (x52)
SyskeyLen : 0 (x00) Incomplete : . (x00)
AuditRBA : 88213108 AuditPos : 512
Continued : N (x00) RecCount : 1 (x01)
TDR Index: 41008 (x0000a030)
GGS tokens:
TokenID x52 'R' ORDBMS Info x00 Length 6 Type ASCII
4f 52 41 43 4c 45 ORACLE
TokenID x4c 'L' LOGCSN Info x00 Length 9 Type ASCII
3230353930313432 205901422
Table ORDERS.ORDER_NOTES
2026/07/09 08:41:06.998.421 FieldComp 1 ORDER_ID
2026/07/09 08:41:06.998.421 FieldComp 2 CUSTOMER_ID
2026/07/09 08:41:06.998.421 FieldComp 3 NOTES
Column 3 (x0003), Len 512 (x0200)
4c 65 20 63 6c 69 65 6e 74 20 61 20 64 65 6d 61 | Le client a dema
6e 64 e9 20 75 6e 20 72 65 6d 62 6f 75 72 73 65 | ndé un remboürse
6d 65 6e 74 20 63 6f 6d 70 6c 65 74 20 61 76 61 | ment complet ava
6e 74 20 6c 61 20 6c 69 76 72 61 69 73 6f 6e 2e | nt la livraison.
The column dump shows Len 512 for the NOTES field — that’s already the byte length as read from the source trail record, before it ever reaches the target apply logic. The source column stores 500 characters, and this note contains accented French text (é, ü) that GoldenGate is representing with multi-byte sequences.
5. Root Cause: Character Set Expansion, Not a Data Problem
This is the detail that matters:
| Source | Target | |
|---|---|---|
| Column definition | VARCHAR2(500 BYTE) |
VARCHAR2(500 BYTE) |
| Database character set | WE8MSWIN1252 |
AL32UTF8 |
| Bytes per accented character | 1 | 2–3 |
Both columns look identical on paper — same length, same byte semantics. But the source database stores Western European text in a single-byte character set, where é and ü cost 1 byte each. GoldenGate correctly converts the data to the target’s character set during apply, and in AL32UTF8, those same accented characters expand to 2–3 bytes. A note that fit comfortably in 500 bytes at the source can exceed 500 bytes once converted — exactly what happened here: 512 bytes of converted UTF-8 data against a 500-byte limit.
This is a common trap in any WE8*/AL32UTF8 migration pair, and it’s invisible from the source side — the row is completely valid there. Logdump is what makes the actual post-conversion byte length visible instead of just trusting the error message’s column name.
6. Fixing It
There are two real options, and the right one depends on whether this is a one-off or a systemic issue across the schema:
Option A — widen the target column using character semantics instead of byte semantics. This is the durable fix if there are more columns like this:
ALTER TABLE target.order_notes MODIFY (notes VARCHAR2(500 CHAR));
CHAR semantics reserve enough bytes per character up front regardless of encoding, so 500 characters of any content fits without recalculating byte budgets per language.
Option B — increase the byte length directly, if you want to keep byte semantics for consistency with the rest of the schema:
ALTER TABLE target.order_notes MODIFY (notes VARCHAR2(1500 BYTE));
Given this was one column and not a schema-wide pattern, Option A was applied here — it fixes this column and any future rows containing multi-byte content without needing to guess a safe byte budget.
7. Resuming Replicat Cleanly
After the DDL fix, do not just START REPLICAT — the failed transaction is still sitting at the abend position and needs to either be skipped (data loss, only acceptable if the row will be reconciled separately) or reprocessed from the same point now that the target can accept it:
# Confirm current position matches the abend point
GGSCI> INFO REPLICAT REP1, DETAIL
# Restart from where it left off — DDL fix means the same record now applies cleanly
GGSCI> START REPLICAT REP1
# Confirm it's running and lag is dropping
GGSCI> LAG REPLICAT REP1
GGSCI> STATS REPLICAT REP1, TOTALSONLY *
Because the fix was schema-side and Replicat wasn’t manually advanced past the bad record, restarting picks the transaction back up and applies it normally — no data loss, no manual reconciliation needed.
Quick Reference: Useful Logdump Commands
| Command | Purpose |
|---|---|
OPEN <file> |
Load a trail file for inspection |
GHDR ON |
Show record headers (timestamp, RBA, operation type) |
DETAIL DATA |
Show actual column values, not just header metadata |
DETAIL ON |
Show column metadata without full data dump |
USETOKEN ON |
Decode GoldenGate tokens (source DB type, CSN, etc.) |
FILTER TABLE <schema.table> |
Only show records for a specific table |
POS <RBA> |
Jump directly to a known byte offset |
NEXT / N |
Read and print the next record |
COUNT |
Count matching records without printing them all |
FILEHEADER ON |
Show the trail file’s own header (created by which process, format version) |
Summary
The error message and column name are a starting point, not the diagnosis. ORA-12899 here looked like a straightforward “data too long” problem, but the source row was valid — the real cause only became visible by reading the raw byte length Logdump reported for the record as it existed in the trail, which exposed the WE8MSWIN1252 → AL32UTF8 expansion. Any time an apply error doesn’t make sense given the source data you can see in the source database directly, pull the actual record out of the trail file before assuming the error message is telling the whole story.