linshenkx/prompt-optimizer · error · Error

Unable to safely analyze remote snapshot assets because ${fa

Error message

Unable to safely analyze remote snapshot assets because ${failures.length} snapshot manifest(s) could not be read. First failure: ${firstFailure.path}: ${firstFailure.message}

What it means

Thrown by analyzeRemoteSnapshotAssetCleanup in remote-snapshot-backup.ts after it attempts to read every remote snapshot manifest and collects failures. Because cleanup analysis must classify each snapshot's assets to decide what is safe to delete, an unreadable manifest makes the whole analysis unsafe, so the function aborts with the count and the first failing path/message.

Source

Thrown at packages/ui/src/utils/remote-snapshot-backup.ts:655

  const entries = await objectStore.list(joinRemotePath(REMOTE_SNAPSHOT_ROOT, 'snapshots'))
  const manifestEntries = entries.filter((entry) => entry.path.endsWith(`/${MANIFEST_FILE_NAME}`))
  const manifests: RemoteSnapshotManifest[] = []
  const failures: Array<{ path: string; message: string }> = []

  for (const entry of manifestEntries) {
    try {
      manifests.push(parseManifest(await objectStore.getText(entry.path)))
    } catch (error) {
      failures.push({
        path: entry.path,
        message: (error as Error).message || String(error),
      })
    }
  }

  if (failures.length > 0) {
    const firstFailure = failures[0]
    throw new Error(
      `Unable to safely analyze remote snapshot assets because ${failures.length} snapshot manifest(s) could not be read. First failure: ${firstFailure.path}: ${firstFailure.message}`,
    )
  }

  return manifests
}

const isCleanupCandidateOldEnough = (
  entry: Pick<RemoteObjectEntry, 'updatedAt'>,
  nowMs: number,
  minimumAgeMs: number,
): boolean => {
  if (minimumAgeMs <= 0) return true
  if (!entry.updatedAt) return false
  const updatedAtMs = Date.parse(entry.updatedAt)
  return Number.isFinite(updatedAtMs) && nowMs - updatedAtMs >= minimumAgeMs
}

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Check the reported first failure path and message to see whether it is a network/permission problem or corrupted JSON
  2. Retry the operation if the message indicates a transient network failure
  3. Repair or remove the broken snapshot entry (delete the orphaned manifest/asset keys for that snapshot) and re-run the analysis
  4. Verify object-store credentials and bucket policy grant read access to all snapshot prefixes
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate manifest readability before analysis
const manifests = await Promise.all(snapshotIds.map(async (id) => {
  try { return await store.get(`snapshots/${id}/manifest.json`) } catch { return null }
}))
if (manifests.some((m) => m === null)) skipCleanup()

Type guard

const isReadableManifest = (value: unknown): value is SnapshotManifest =>
  typeof value === 'object' && value !== null && 'id' in value && 'assets' in value

Try / catch

try {
  await cleanupRemoteSnapshotAssets(store, onProgress)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Unable to safely analyze')) {
    // log and skip cleanup; do not delete anything
  } else throw error
}

Prevention

When it happens

Trigger: Calling analyzeRemoteSnapshotAssetCleanup (or cleanupRemoteSnapshotAssets, which calls it first) when one or more snapshot manifest JSON objects on the remote object store are missing, corrupted, truncated, or return access/network errors during listing+get.

Common situations: A previous backup upload was interrupted leaving a partial manifest; the remote bucket was edited/deleted manually; credentials lost read permission on some keys; transient network errors or bucket rate limits during manifest reads.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/3d1bd1bcb317382f. Report an issue: GitHub.