hcengineering/platform · error · Error

has no snapshot at

Error message

${infoFile} has no snapshot at ${date}

What it means

resolveSnapshots throws this Error when a specific date filter is requested (date !== -1) but no snapshot in backup.json.gz has that exact date. The check tool can only resolve snapshots by exact timestamp match, not nearest-before.

Solutions

  1. List snapshot dates from backup.json.gz and pass an exact existing timestamp.
  2. Use date = -1 to check against the latest snapshot.
  3. Check millisecond precision — snapshot dates are epoch millis.
  4. Use a manifest from a backup run that actually contains the desired snapshot.

Example fix

// resolve by exact stored date
// before
await resolved(ctx, storage, 1699999999) // seconds, no match
// after
await resolved(ctx, storage, 1699999999000) // exact snapshot date in ms, or -1
Defensive patterns

Strategy: validation

Validate before calling

// resolve an exact snapshot date from the manifest first
const info = JSON.parse(gunzipSync(new Uint8Array(await storage.loadFile('backup.json.gz'))).toString())
if (!info.snapshots.some((s: any) => s.date === requestedDate)) {
  throw new Error(`No snapshot at ${requestedDate}; use an exact snapshot date or -1`)
}

Type guard

function hasSnapshot(manifest: { snapshots: { date: number }[] }, date: number): boolean {
  return date === -1 || manifest.snapshots.some(s => s.date === date)
}

Try / catch

try {
  await runCheck(ctx, storage, date)
} catch (err) {
  if (err instanceof Error && err.message.includes('has no snapshot at')) {
    // list available dates and let the user choose
  } else throw err
}

Prevention

When it happens

Trigger: Calling the backup check flow with a date parameter that does not exactly equal any snapshot's date field in the manifest, causing findIndex to return -1.

Common situations: Hand-copying a timestamp with wrong precision (ms vs s) or timezone shifts; requesting a date between snapshots; a snapshot with that date was pruned from a newer manifest.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/77e74c07413ef823. Report an issue: GitHub.

Appendix: source

Thrown at server/backup/src/check.ts:77

  blobs: BlobCheckResult
  ok: boolean
}

async function resolveSnapshots (
  storage: BackupStorage,
  date: number
): Promise<{ backupInfo: BackupInfo, snapshots: BackupSnapshot[], date: number }> {
  const infoFile = 'backup.json.gz'
  if (!(await storage.exists(infoFile))) {
    throw new Error(`${infoFile} should present to check`)
  }
  const backupInfo: BackupInfo = JSON.parse(gunzipSync(new Uint8Array(await storage.loadFile(infoFile))).toString())

  let snapshots = backupInfo.snapshots
  if (date !== -1) {
    const bk = backupInfo.snapshots.findIndex((it) => it.date === date)
    if (bk === -1) {
      throw new Error(`${infoFile} has no snapshot at ${date}`)
    }
    snapshots = backupInfo.snapshots.slice(0, bk + 1)
  } else {
    date = snapshots[snapshots.length - 1]?.date ?? -1
  }
  return { backupInfo, snapshots, date }
}

/**
 * Checks whether all documents recorded in a backup are present, and unchanged, in the given
 * workspace's document domains, and whether every backed-up blob's content exists in blob
 * storage (see {@link checkWorkspaceBlobs}).
 *
 * This is read-only: nothing is uploaded, removed, or otherwise modified in either the workspace
 * or the backup. It is meant as a diagnostic to run before trusting a backup (or after a restore)
 * — to find out if the workspace is missing data the backup has, without acting on it.
 *
 * Account domains (person/socialId) are skipped, since they live in the account database rather

View on GitHub (pinned to 63e28dc964)