👟 Reproduction steps
On any self-hosted Appwrite 1.9.x installation, every daily maintenance run (default _APP_MAINTENANCE_START_TIME=00:00) emits an unhandled Utopia\Database\Exception\NotFound: Collection not found from appwrite-queue-v1-deletes. The error fires once per maintenance tick — predictably at midnight UTC for default-configured installs — and lights up Sentry / error logs every single day.
To reproduce on a clean install:
- Install Appwrite 1.9.x and let
appwrite-task-maintenance enqueue its daily job.
- Watch
appwrite-worker-deletes logs at the next _APP_MAINTENANCE_START_TIME.
- Observe the exception below.
👍 Expected behavior
Daily maintenance completes silently. deleteOldDeployments should either skip projects whose schema does not declare the functions / sites collections, or maintenance should not enqueue this delete type for the console project.
👎 Actual Behavior
Every maintenance tick throws:
Utopia\Database\Exception\NotFound: Collection not found
at /usr/src/code/vendor/utopia-php/database/src/Database/Database.php:8292
Utopia\Database\Database->find('functions', [...])
at /usr/src/code/src/Appwrite/Platform/Workers/Deletes.php:1469 (listByGroup)
at /usr/src/code/src/Appwrite/Platform/Workers/Deletes.php:420 (deleteOldDeployments)
at /usr/src/code/src/Appwrite/Platform/Workers/Deletes.php:218 (action — DELETE_TYPE_MAINTENANCE)
Root cause
Maintenance.php:62-91 enqueues a DELETE_TYPE_MAINTENANCE job for every accessed tenant project and explicitly for the $console project itself:
$queueForDeletes
->setType(DELETE_TYPE_MAINTENANCE)
->setProject($console)
...
->trigger();
The handler at Deletes.php:218 routes that into deleteOldDeployments, which at :420 calls:
$this->listByGroup('functions', [], $dbForProject, $removalCallback);
$this->listByGroup('sites', [], $dbForProject, $removalCallback);
listByGroup then runs $database->find($collection, …) (:1469), which throws NotFoundException at Database.php:8292 because the console schema (defined in app/config/collections/platform.php) does not declare functions, sites, or deployments collections — those are tenant-project collections defined in app/config/collections/projects.php.
Verification
On the affected install (single tenant project + console):
-- tenant project (works):
SELECT _uid FROM _5__metadata WHERE _uid IN ('functions','sites','deployments');
-- returns: deployments, functions, sites
-- console project (throws):
SELECT _uid FROM _console__metadata WHERE _uid IN ('functions','sites','deployments');
-- returns: (empty)
Tenant-project maintenance succeeds; console-project maintenance throws on every tick.
Likely regression
Introduced in #10959 — Feat: Auto-delete deployments (merged Dec 2025), shipped via the schema-migration bundle #10862. The migration set up tenant-project collections but the new cross-project maintenance loop targets the console project as well, where these collections were never expected to exist.
🤖 Suggested fix
Either of these changes resolves it cleanly:
Option A — guard deleteOldDeployments (smallest change). In Workers/Deletes.php::deleteOldDeployments, skip when the schema does not declare the collection:
foreach (['functions', 'sites'] as $group) {
if ($dbForProject->getCollection($group)->isEmpty()) {
continue;
}
$this->listByGroup($group, [], $dbForProject, $removalCallback);
}
Option B — don't enqueue the console job for this delete type. In Tasks/Maintenance.php, the per-project loop already covers tenant projects; the explicit $console enqueue (lines 89-91) is for console-only cleanup tasks (audit, cache, schedules) and shouldn't trigger deleteOldDeployments. Either split DELETE_TYPE_MAINTENANCE into a console-scoped subtype, or have the Deletes worker branch on $project->getId() === 'console' and skip deployment cleanup.
I'd lean toward A because it's the most defensive: it also protects against any future per-project schema drift where a project might legitimately not host functions/sites.
🎲 Versions
- Appwrite: 1.9.x (self-hosted)
- Reproduces on default
_APP_MAINTENANCE_START_TIME=00:00, _APP_MAINTENANCE_INTERVAL=86400
- Single-tenant install — but happens with any number of tenants because the issue is on the console-project iteration
➕ Additional Information
Related upstream issue I previously filed against the same release line: #12200 (scheduler localhost endpoint). Happy to send a PR for either suggested fix above if helpful.
👟 Reproduction steps
On any self-hosted Appwrite 1.9.x installation, every daily maintenance run (default
_APP_MAINTENANCE_START_TIME=00:00) emits an unhandledUtopia\Database\Exception\NotFound: Collection not foundfromappwrite-queue-v1-deletes. The error fires once per maintenance tick — predictably at midnight UTC for default-configured installs — and lights up Sentry / error logs every single day.To reproduce on a clean install:
appwrite-task-maintenanceenqueue its daily job.appwrite-worker-deleteslogs at the next_APP_MAINTENANCE_START_TIME.👍 Expected behavior
Daily maintenance completes silently.
deleteOldDeploymentsshould either skip projects whose schema does not declare thefunctions/sitescollections, or maintenance should not enqueue this delete type for the console project.👎 Actual Behavior
Every maintenance tick throws:
Root cause
Maintenance.php:62-91enqueues aDELETE_TYPE_MAINTENANCEjob for every accessed tenant project and explicitly for the$consoleproject itself:The handler at
Deletes.php:218routes that intodeleteOldDeployments, which at:420calls:listByGroupthen runs$database->find($collection, …)(:1469), which throwsNotFoundExceptionatDatabase.php:8292because theconsoleschema (defined inapp/config/collections/platform.php) does not declarefunctions,sites, ordeploymentscollections — those are tenant-project collections defined inapp/config/collections/projects.php.Verification
On the affected install (single tenant project + console):
Tenant-project maintenance succeeds; console-project maintenance throws on every tick.
Likely regression
Introduced in #10959 — Feat: Auto-delete deployments (merged Dec 2025), shipped via the schema-migration bundle #10862. The migration set up tenant-project collections but the new cross-project maintenance loop targets the console project as well, where these collections were never expected to exist.
🤖 Suggested fix
Either of these changes resolves it cleanly:
Option A — guard
deleteOldDeployments(smallest change). InWorkers/Deletes.php::deleteOldDeployments, skip when the schema does not declare the collection:Option B — don't enqueue the console job for this delete type. In
Tasks/Maintenance.php, the per-project loop already covers tenant projects; the explicit$consoleenqueue (lines 89-91) is for console-only cleanup tasks (audit, cache, schedules) and shouldn't triggerdeleteOldDeployments. Either splitDELETE_TYPE_MAINTENANCEinto a console-scoped subtype, or have theDeletesworker branch on$project->getId() === 'console'and skip deployment cleanup.I'd lean toward A because it's the most defensive: it also protects against any future per-project schema drift where a project might legitimately not host functions/sites.
🎲 Versions
_APP_MAINTENANCE_START_TIME=00:00,_APP_MAINTENANCE_INTERVAL=86400➕ Additional Information
Related upstream issue I previously filed against the same release line: #12200 (scheduler localhost endpoint). Happy to send a PR for either suggested fix above if helpful.