overleaf/overleaf · warning · BadRequestError
requested version past the end of the history
Error message
requested version past the end of the history
What it means
getChangesInChunkSince throws Errors.BadRequestError when sinceVersion is greater than the latest chunk's end version, meaning the caller asked for changes since a version that is beyond the end of the project's recorded history. It protects against invalid version queries.
Source
Thrown at services/project-history/app/js/SnapshotManager.js:238
const changes = chunk.getChanges()
snapshot.applyAll(changes)
return {
snapshot,
version: chunk.getEndVersion(),
}
}
async function getChangesInChunkSince(projectId, historyId, sinceVersion) {
const latestChunk = Core.Chunk.fromRaw(
(
await HistoryStoreManager.promises.getMostRecentChunk(
projectId,
historyId
)
).chunk
)
if (sinceVersion > latestChunk.getEndVersion()) {
throw new Errors.BadRequestError(
'requested version past the end of the history'
)
}
const latestStartVersion = latestChunk.getStartVersion()
let chunk = latestChunk
if (sinceVersion < latestStartVersion) {
chunk = Core.Chunk.fromRaw(
(
await HistoryStoreManager.promises.getChunkAtVersion(
projectId,
historyId,
sinceVersion
)
).chunk
)
}
const changes = chunk
.getChanges()View on GitHub (pinned to 28ad3b03b7)
Solutions
- Clamp/validate sinceVersion against the history's end version before calling.
- After a hard resync, clients must re-fetch the current version instead of reusing old ones.
- Return 400 to the caller and have it reset its local version tracking.
- Verify the correct historyId is being used for the project.
Example fix
// before
const changes = await SnapshotManager.promises.getChangesInChunkSince(projectId, historyId, sinceVersion)
// after
const latestChunk = (await ChunkManager.promises.getLatestChunk(projectId, historyId)).chunk
if (sinceVersion > latestChunk.getEndVersion()) {
sinceVersion = latestChunk.getEndVersion() // or reset client state
}
const changes = await SnapshotManager.promises.getChangesInChunkSince(projectId, historyId, sinceVersion) Defensive patterns
Strategy: validation
Validate before calling
const latestChunk = (await ChunkManager.promises.getLatestChunk(projectId, historyId)).chunk
if (sinceVersion > latestChunk.getEndVersion()) {
sinceVersion = latestChunk.getEndVersion()
} Try / catch
try {
await SnapshotManager.promises.getChangesInChunkSince(projectId, historyId, sinceVersion)
} catch (err) {
if (err instanceof Errors.BadRequestError && err.message.includes('past the end')) {
// reset client version tracking and re-sync from latest
} else {
throw err
}
} Prevention
- Clamp sinceVersion to the history's end version before querying.
- Invalidate cached versions after resyncs/history rewrites.
- Always pair version queries with the correct historyId.
- Have clients re-fetch latest version on 400 responses.
When it happens
Trigger: Calling getChangesInChunkSince(projectId, historyId, sinceVersion) where sinceVersion > latestChunk.getEndVersion() — e.g. a stale client sends a version from a different/forked history or an out-of-range number.
Common situations: Clients caching a version from before a history reset or resync; hard resync rewrote history so old versions no longer exist; off-by-one or wrong project's version sent to another project's history; replaying updates after history truncation.
Related errors
- Invalid sorting criteria
- invalid compiler
- cipherLabel cannot be empty
- cipherLabel must not contain a colon (:), got ${cipherLabel}
- cipherLabel must contain version suffix (e.g. 2042.1-v42), g
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/2b85331e82701ac1.
Report an issue: GitHub.