linshenkx/prompt-optimizer · error · Error

Invalid app backup package manifest

Error message

Invalid app backup package manifest

What it means

Thrown by parseManifest (called from readDataManagerResourcePackage in packages/ui/src/utils/data-manager-resource-package.ts) when the unzipped backup's manifest.json fails structural validation: schemaVersion must equal DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION, appDataPath must equal APP_DATA_JSON_PATH, favoritesPath must equal FAVORITES_JSON_PATH, and resources/missingResources must be arrays. It means the zip is not a valid app backup package produced by this code's exporter. It protects the restore path from partially written or foreign archives.

Source

Thrown at packages/ui/src/utils/data-manager-resource-package.ts:160

  ]
}

const isRecord = (value: unknown): value is Record<string, unknown> =>
  !!value && typeof value === 'object' && !Array.isArray(value)

const textToZipBytes = (text: string): Uint8Array => copyBytes(strToU8(text))

const parseManifest = (json: string): DataManagerResourcePackageManifest => {
  const parsed = JSON.parse(json) as unknown
  if (
    !isRecord(parsed) ||
    parsed.schemaVersion !== DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION ||
    parsed.appDataPath !== APP_DATA_JSON_PATH ||
    parsed.favoritesPath !== FAVORITES_JSON_PATH ||
    !Array.isArray(parsed.resources) ||
    !Array.isArray(parsed.missingResources)
  ) {
    throw new Error('Invalid app backup package manifest')
  }
  return parsed as DataManagerResourcePackageManifest
}

const collectStoreResources = async (
  config: ImageStoreExportConfig,
  files: Record<string, Uint8Array>,
): Promise<{
  resources: DataManagerResourceManifestEntry[]
  missing: Array<{ store: DataManagerImageStoreKey; id: string }>
}> => {
  if (!config.service) {
    return { resources: [], missing: [] }
  }

  const metadataList = await config.service.listAllMetadata()
  const resources: DataManagerResourceManifestEntry[] = []
  const missing: Array<{ store: DataManagerImageStoreKey; id: string }> = []

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Verify the package was exported by the same app version (or a version sharing the same DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION); re-export the backup from the source app
  2. Unzip the archive and inspect manifest.json: confirm schemaVersion, appDataPath and favoritesPath values and that resources/missingResources are arrays
  3. If you maintain the exporter, regenerate the package rather than hand-editing the manifest
  4. If supporting cross-version restores, add a migration step that upgrades older manifests to the current schemaVersion before validation

Example fix

// before
const pkg = readDataManagerResourcePackage(bytes) // throws: Invalid app backup package manifest

// after
const manifest = JSON.parse(strFromU8(unzipSync(bytes)['manifest.json']))
if (manifest.schemaVersion !== DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION) {
  throw new Error(`Unsupported backup schema version: ${manifest.schemaVersion}`)
}
const pkg = readDataManagerResourcePackage(bytes)
Defensive patterns

Strategy: validation

Validate before calling

import { unzipSync } from 'fflate'
import { strFromU8 } from 'fflate'

const isValidAppBackupManifest = (json: string): boolean => {
  try {
    const m = JSON.parse(json)
    return (
      typeof m === 'object' && m !== null &&
      m.schemaVersion === DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION &&
      m.appDataPath === 'app-data.json' &&
      m.favoritesPath === 'favorites.json' &&
      Array.isArray(m.resources) &&
      Array.isArray(m.missingResources)
    )
  } catch {
    return false
  }
}

// before readDataManagerResourcePackage:
const files = unzipSync(bytes)
const ok = !!files['manifest.json'] && isValidAppBackupManifest(strFromU8(files['manifest.json']))

Type guard

const isAppBackupManifest = (v: unknown): v is DataManagerResourcePackageManifest =>
  typeof v === 'object' && v !== null &&
  (v as DataManagerResourcePackageManifest).schemaVersion === DATA_MANAGER_RESOURCE_PACKAGE_SCHEMA_VERSION &&
  Array.isArray((v as DataManagerResourcePackageManifest).resources) &&
  Array.isArray((v as DataManagerResourcePackageManifest).missingResources)

Try / catch

try {
  const pkg = readDataManagerResourcePackage(bytes)
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid app backup package manifest') {
    // show 'incompatible or corrupted backup' UI; do not retry
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling readDataManagerResourcePackage on a zip whose manifest.json has a mismatched schemaVersion (package written by an older/newer app version), wrong appDataPath/favoritesPath values, or missing/non-array resources or missingResources fields. Also triggered by a hand-edited or truncated manifest.json, or JSON.parse succeeding but yielding a non-record (e.g. an array or string).

Common situations: Restoring a backup created by a different app version after a schema migration; renaming the internal app-data.json/favorites.json files inside the zip; passing a generic zip that happens to contain a manifest.json; corrupting the manifest during download/transfer. Note JSON.parse failures throw a SyntaxError before this check, so this error specifically means parseable-but-invalid content.

Related errors


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