passbolt/passbolt_api · error · InternalErrorException
Unable to migrate folder ID
Error message
Unable to migrate folder ID: {0} to V5. {exceptionMessage} What it means
Thrown by updateFolder() when patching and saving a folder with its V5 metadata fails (validation or persistence error via saveOrFail). It wraps the original exception's message into an InternalErrorException with a 500 status, and migratePersonal/migrateShared propagate it. The migration service catches it per-folder and records the error in the migration result, so the migration aborts for that folder only.
Solutions
- Read the appended exception message in the error output; it names the exact validation field or database error that made saveOrFail() fail.
- Fix the underlying database issue (disk space, connection, lock) and re-run the migration command.
- Verify the folder row is consistent: metadata fields nullable constraints, metadata_key_id references an existing metadata_keys row.
- Ensure the metadata plugin migrations are up to date (`ddev refresh` or run migrations) before migrating.
- If a specific folder is corrupt, repair or delete/recreate it, then re-run migration.
Example fix
// diagnosis: appended message says "_metadata_key_id: The provided value is invalid" // before $metadata_key_id => $metadataKey->id (deleted/expired key row) // after $metadataKey = $this->getMetadataKeyForEncryption(); // re-fetch latest active key and re-run migration
Defensive patterns
Strategy: try-catch
Validate before calling
// before running the migration
$foldersTable = \Cake\ORM\Locator\LocatorAwareTrait::fetchTable('Folders');
$broken = $foldersTable->find()->where(function ($exp, $q) {
return $exp->isNull('metadata_key_id'); // or other preconditions
})->count(); Type guard
if (!($folder instanceof \Passbolt\Folders\Model\Entity\Folder) || $folder->id === null) { return; } Try / catch
try {
(new MigrateAllV4FoldersToV5Service())->migrate();
} catch (\Cake\Http\Exception\InternalErrorException $e) {
// inspect $e->getMessage() for the wrapped validation/db error, fix, re-run
} Prevention
- Run plugin migrations before the V4->V5 data migration.
- Check disk space and DB connectivity on the host before bulk migrations.
- Run the migration on a staging copy first.
- Inspect the result['errors'] array after migrate() instead of assuming all folders succeeded.
When it happens
Trigger: Calling migratePersonal() or migrateShared() on a V4 folder leads to updateFolder(), where FoldersTable->patchEntity(..., ['validate' => 'v5']) produces validation errors (e.g. metadata, metadata_key_id or metadata_key_type invalid under the v5 validation ruleset), or saveOrFail() fails (database constraint/write failure).
Common situations: Database write failures during a bulk V4-to-V5 folder migration (disk full, lock timeout, connection dropped); the v5 validation ruleset rejecting the patched data such as a null/empty metadata field or an invalid metadata_key_id UUID; running the metadata migration command on an instance with partially applied metadata schema changes.
Related errors
- The tag metadata key data could not be updated.
- The user identifier should be a UUID.
- " " is not a valid search filter.
- " " is not a valid search filter. It is not a UTF8 string.
- " " is not a valid search filter. It should be between 1…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/cb4104474131db58.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Metadata/src/Service/Migration/MigrateAllV4FoldersToV5Service.php:239
* @return void
*/
private function updateFolder(Folder $folder, array $data): void
{
try {
$folder = $this->Folders->patchEntity($folder, $data, [
'accessibleFields' => [
'name' => true,
'metadata' => true,
'metadata_key_id' => true,
'metadata_key_type' => true,
],
'validate' => 'v5',
]);
$this->Folders->saveOrFail($folder, ['checkRules' => false]);
} catch (Exception $exception) {
$msg = __('Unable to migrate folder ID: {0} to V5.', $folder->id);
$msg .= ' ' . $exception->getMessage();
throw new InternalErrorException($msg, 500, $exception);
}
}
/**
* @return \Passbolt\Metadata\Model\Entity\MetadataKey
* @throws \Cake\Datasource\Exception\RecordNotFoundException When there is no metadata key record.
*/
private function getMetadataKeyForEncryption(): MetadataKey
{
/** @var \Passbolt\Metadata\Model\Table\MetadataKeysTable $metadataKeysTable */
$metadataKeysTable = $this->fetchTable('Passbolt/Metadata.MetadataKeys');
/** @var \Passbolt\Metadata\Model\Entity\MetadataKey $metadataKey */
$metadataKey = $metadataKeysTable->getLatestActiveKey();
return $metadataKey;
}
View on GitHub (pinned to 31c1bbc10f)