XACT_E_INVALIDLSN (0X8004D084) – lsnToRead outside log limits
This error means the transaction log sequence number you're reading from doesn't exist in the current log file. The fix is to extend the log or change your read offset.
Getting slapped with XACT_E_INVALIDLSN (0x8004D084) is confusing because the error message—lsnToRead is outside of the current limits of the log—sounds like something broke deep in the transaction engine. It's usually not corruption, just a mismatch between where your code wants to read and what the log actually holds.
The Fix: Two paths
You have two real options. Pick based on what you control.
Option 1 – Extend the log file (you own the log)
If you're working with MSDTC or a custom transaction log managed by XactFile or XactLog APIs, the most direct fix is to grow the log so your target LSN falls within its range.
// C++ example – extend the log to include the needed LSN
XactLog *pLog = ...;
XACTLOG_LSN targetLsn = ...; // the LSN you tried reading
XACTLOG_EXTEND_PARAMS extParams = {0};
extParams.cbSize = sizeof(extParams);
extParams.lsnStart = pLog->GetLastLSN(); // extend from current end
extParams.cbLog = 64 * 1024; // 64KB – adjust based on your LSN offset
extParams.fForce = FALSE;
HRESULT hr = pLog->Extend(&extParams);
if (FAILED(hr)) { /* handle – likely out of disk or quota */ }
What's actually happening here is the LSN you're requesting (lsnToRead) is a log sequence number that points to a byte offset inside the log file. If the log hasn't been grown enough, that offset simply doesn't exist yet. Extending the log tells the underlying system to allocate more space, then remap LSNs to the new larger file. Once extended, the read will succeed—assuming your LSN is within the new bounds.
Option 2 – Change the read offset (you're the consumer)
Maybe you don't own the log—you're just reading from someone else's transaction log, like SQL Server's fn_dblog or a backup tool. In that case, you can't extend it. You need to adjust your query or code to read a valid LSN range.
-- T-SQL example – find the current minimum LSN
SELECT MIN([Current LSN]) AS MinLSN
FROM fn_dblog(NULL, NULL);
-- Then adjust your read to start from that LSN or later
The reason this works is simple: the log is a circular file. Old LSNs get truncated over time (checkpoints, log backups). If you try to read an LSN that was already pruned, you'll get this error. You need to read backward from the current LSN, not forward from some stale number.
Why this error really happens
Under the hood, XACT_E_INVALIDLSN is returned by the IXactLog::Read method when the lsnToRead parameter is less than the log's lsnMin or greater than lsnMax. The log internally tracks these limits. It's not a corruption error—it's a range check that failed.
Common triggers:
- You restored a backup but tried to read an LSN from the old backup's log chain
- Your code cached an LSN from a previous session and the log has since been truncated
- You're reading from a secondary replica's log that hasn't caught up (in SQL Server Always On)
Less common edge cases
These don't hit often but will waste your afternoon if you don't know them.
Case 1 – MSDTC log corruption
If the MSDTC transaction log (MSDTC.LOG in %SystemRoot%\System32\DTCLog) has a corrupted header, the min/max LSNs stored there might be bogus. You'd get XACT_E_INVALIDLSN on every read because the internal range is effectively empty. The fix here isn't extending—it's rebuilding the log.
net stop msdtc
msdtc -resetlog
net start msdtc
This wipes the log. Only do it if you're sure no active distributed transactions exist. You'll lose any in-flight transactions, but the error goes away.
Case 2 – VMware snapshot with Transactional VSS
Some backup software uses VSS writers to quiesce the application log before taking a snapshot. If the snapshot is taken after the log wraps around, the LSN state in the snapshot's metadata points to an offset that no longer exists in the actual log. The result is this error when you try to restore. The fix: take a new backup after the log has been backed up and truncated cleanly.
Case 3 – Misaligned log file size
The XACT log implementation expects the log file size to be a multiple of its internal sector size (usually 512 bytes). If someone created the log with a weird size (e.g., 12345 bytes), the LSN mapping can go out of bounds. Re-create the log with CreateFile and a proper size aligned to 512-byte boundaries.
Prevention – stop it from coming back
None of this is hard to prevent if you're disciplined.
- Don't cache LSNs across application restarts or log truncations. Always query the current min/max LSN before reading.
- Size your logs generously from the start. A log that grows dynamically is fine, but if you pre-allocate enough space, you'll never hit the upper bound mid-operation.
- Monitor log growth with a simple perfmon counter (
Log File Sizefor MSDTC, orLog Size (MB)for SQL Server). Set an alert at 80%. - Test your backup/restore chain with LSN-based recovery. Restore to a point-in-time using
STOPATand confirm the LSN you target actually exists in the backup set.
One last thing: if you see this error in a production SQL Server database, check DBCC LOGINFO first. It shows you the VLFs and their status. A stuck VLF marked as active when it shouldn't be can cause the log to appear smaller than it really is. Fix that with a log backup or a manual checkpoint.
Was this solution helpful?