jlcodes99/cockpit-tools · error

invalid_bundle_root

invalid_bundle_root

Error message

invalid_bundle_root

What it means

parseAccountTransferBundle rejects a transfer bundle whose parsed root is not a JSON object (a record). The importer expects Record<PlatformId, AccountTransferPlatformPayload>-shaped input, so arrays, strings, numbers, or null at the root trigger this code.

Source

Thrown at src/services/accountTransferService.ts:331

    version: ACCOUNT_TRANSFER_VERSION,
    exported_at: new Date().toISOString(),
    summary: {
      platform_count: ALL_PLATFORM_IDS.length,
      account_count: accountCount,
    },
    platforms,
  };
}

export async function exportAllAccountsTransferJson(): Promise<string> {
  const bundle = await buildAccountTransferBundle();
  return JSON.stringify(bundle, null, 2);
}

function parseAccountTransferBundle(jsonContent: string): Record<PlatformId, AccountTransferPlatformPayload> {
  const parsed = parseJsonOrThrow(jsonContent, 'invalid_json');
  if (!isRecord(parsed)) {
    throw new Error('invalid_bundle_root');
  }

  if (parsed.schema !== ACCOUNT_TRANSFER_SCHEMA) {
    throw new Error('invalid_bundle_schema');
  }

  if (parsed.version !== ACCOUNT_TRANSFER_VERSION) {
    throw new Error('invalid_bundle_version');
  }

  const rawPlatforms = parsed.platforms;
  if (!isRecord(rawPlatforms)) {
    throw new Error('invalid_bundle_platforms');
  }

  const platforms: Record<PlatformId, AccountTransferPlatformPayload> = {} as Record<
    PlatformId,
    AccountTransferPlatformPayload

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Ensure the bundle's top level is a JSON object containing schema, version, and platforms keys
  2. Re-export the bundle with exportAccountTransferBundle so the wrapper object is produced
  3. Wrap arrays in an object or remove the extra outer array layer
  4. Check the file was not truncated after an opening brace or exported from a different schema

Example fix

// before
[ { "openai": { ... } } ]
// after
{ "schema": "...", "version": 1, "platforms": { "openai": { ... } } }
Defensive patterns

Strategy: validation

Validate before calling

const obj = JSON.parse(text);
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
  throw new Error('invalid_bundle_root');
}

Type guard

function isBundleRoot(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v) && 'platforms' in v;
}

Try / catch

try {
  const bundle = importAccountTransferBundle(text);
} catch (e) {
  if (e instanceof Error && e.message === 'invalid_bundle_root') {
    alert('Import file must be a transfer bundle object, not an array or scalar.');
  } else throw e;
}

Prevention

When it happens

Trigger: The JSON string parses successfully (via parseJsonOrThrow) but isRecord(parsed) is false — e.g. the file contains a top-level array '[...]', a bare string, number, boolean, or null.

Common situations: Hand-editing a bundle into an array of platforms, exporting only an inner section instead of the full bundle, pasting a fragment of a bundle.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/681bece66af5de41. Report an issue: GitHub.