hcengineering/platform · error · Error

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

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.

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)

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.