The original steps to reproduce were repeating the export http request quickly to trigger that database state. I was able to reproduce, but by adding sleep(3) after checkJobAndGetUser / before queueExportJob.
{
"reqId": "30qemcHmWkQrs9dsUsxO",
"level": 3,
"time": "2026-03-18T14:44:47+00:00",
"remoteAddr": "172.18.0.1",
"user": "bob",
"app": "no app in context",
"method": "GET",
"url": "/ocs/v2.php/apps/user_migration/api/v1/status",
"scriptName": "/ocs/v2.php",
"message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"version": "33.0.0.16",
"exception": {
"Exception": "OCP\\AppFramework\\Db\\MultipleObjectsReturnedException",
"Message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ",
"Code": 0,
"Trace": [
{
"file": "/var/www/html/lib/public/AppFramework/Db/QBMapper.php",
"line": 382,
"function": "findOneQuery",
"class": "OCP\\AppFramework\\Db\\QBMapper",
"type": "->",
"args": [
{
"__class__": "OC\\DB\\QueryBuilder\\QueryBuilder"
}
]
},
{
"file": "/var/www/html/apps-writable/user_migration/lib/Db/UserExportMapper.php",
"line": 46,
"function": "findEntity",
"class": "OCP\\AppFramework\\Db\\QBMapper",
"type": "->",
"args": [
{
"__class__": "OC\\DB\\QueryBuilder\\QueryBuilder"
}
]
},
{
"file": "/var/www/html/apps-writable/user_migration/lib/Service/UserMigrationService.php",
"line": 481,
"function": "getBySourceUser",
"class": "OCA\\UserMigration\\Db\\UserExportMapper",
"type": "->",
"args": [
"bob"
]
},
{
"file": "/var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php",
"line": 67,
"function": "getCurrentJob",
"class": "OCA\\UserMigration\\Service\\UserMigrationService",
"type": "->",
"args": [
{
"__class__": "OC\\User\\User"
}
]
},
{
"file": "/var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php",
"line": 114,
"function": "getCurrentJobData",
"class": "OCA\\UserMigration\\Controller\\ApiController",
"type": "->",
"args": [
{
"__class__": "OC\\User\\User"
}
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
"line": 205,
"function": "status",
"class": "OCA\\UserMigration\\Controller\\ApiController",
"type": "->",
"args": []
},
{
"file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
"line": 118,
"function": "executeController",
"class": "OC\\AppFramework\\Http\\Dispatcher",
"type": "->",
"args": [
{
"__class__": "OCA\\UserMigration\\Controller\\ApiController"
},
"status"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/App.php",
"line": 153,
"function": "dispatch",
"class": "OC\\AppFramework\\Http\\Dispatcher",
"type": "->",
"args": [
{
"__class__": "OCA\\UserMigration\\Controller\\ApiController"
},
"status"
]
},
{
"file": "/var/www/html/lib/private/Route/Router.php",
"line": 321,
"function": "main",
"class": "OC\\AppFramework\\App",
"type": "::",
"args": [
"OCA\\UserMigration\\Controller\\ApiController",
"status",
{
"__class__": "OC\\AppFramework\\DependencyInjection\\DIContainer"
},
{
"apiVersion": "1",
"_route": "ocs.user_migration.api.status"
}
]
},
{
"file": "/var/www/html/ocs/v1.php",
"line": 61,
"function": "match",
"class": "OC\\Route\\Router",
"type": "->",
"args": [
"/ocsapp/apps/user_migration/api/v1/status"
]
},
{
"file": "/var/www/html/ocs/v2.php",
"line": 8,
"args": [
"/var/www/html/ocs/v1.php"
],
"function": "require_once"
}
],
"File": "/var/www/html/lib/public/AppFramework/Db/QBMapper.php",
"Line": 293,
"message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ",
"exception": "{\"class\":\"OCP\\AppFramework\\Db\\MultipleObjectsReturnedException\",\"message\":\"Did not expect more than one result when executing: query \\\"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\\\"; \",\"code\":0,\"file\":\"/var/www/html/lib/public/AppFramework/Db/QBMapper.php:293\",\"trace\":\"#0 /var/www/html/lib/public/AppFramework/Db/QBMapper.php(382): OCP\\AppFramework\\Db\\QBMapper->findOneQuery(Object(OC\\DB\\QueryBuilder\\QueryBuilder))\\n#1 /var/www/html/apps-writable/user_migration/lib/Db/UserExportMapper.php(46): OCP\\AppFramework\\Db\\QBMapper->findEntity(Object(OC\\DB\\QueryBuilder\\QueryBuilder))\\n#2 /var/www/html/apps-writable/user_migration/lib/Service/UserMigrationService.php(481): OCA\\UserMigration\\Db\\UserExportMapper->getBySourceUser('bob')\\n#3 /var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php(67): OCA\\UserMigration\\Service\\UserMigrationService->getCurrentJob(Object(OC\\User\\User))\\n#4 /var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php(114): OCA\\UserMigration\\Controller\\ApiController->getCurrentJobData(Object(OC\\User\\User))\\n#5 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(205): OCA\\UserMigration\\Controller\\ApiController->status()\\n#6 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(118): OC\\AppFramework\\Http\\Dispatcher->executeController(Object(OCA\\UserMigration\\Controller\\ApiController), 'status')\\n#7 /var/www/html/lib/private/AppFramework/App.php(153): OC\\AppFramework\\Http\\Dispatcher->dispatch(Object(OCA\\UserMigration\\Controller\\ApiController), 'status')\\n#8 /var/www/html/lib/private/Route/Router.php(321): OC\\AppFramework\\App::main('OCA\\\\UserMigrati...', 'status', Object(OC\\AppFramework\\DependencyInjection\\DIContainer), Array)\\n#9 /var/www/html/ocs/v1.php(61): OC\\Route\\Router->match('/ocsapp/apps/us...')\\n#10 /var/www/html/ocs/v2.php(8): require_once('/var/www/html/o...')\\n#11 {main}\"}",
"CustomMessage": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; "
}
}
Enforce that there's only one export job by adding a unique constraint or make the service more relaxed.
How to use GitHub
Steps to reproduce
Execute 2x
The original steps to reproduce were repeating the export http request quickly to trigger that database state. I was able to reproduce, but by adding sleep(3) after
checkJobAndGetUser/ beforequeueExportJob.Expected behaviour
Api status request fails hard
{ "reqId": "30qemcHmWkQrs9dsUsxO", "level": 3, "time": "2026-03-18T14:44:47+00:00", "remoteAddr": "172.18.0.1", "user": "bob", "app": "no app in context", "method": "GET", "url": "/ocs/v2.php/apps/user_migration/api/v1/status", "scriptName": "/ocs/v2.php", "message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ", "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36", "version": "33.0.0.16", "exception": { "Exception": "OCP\\AppFramework\\Db\\MultipleObjectsReturnedException", "Message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ", "Code": 0, "Trace": [ { "file": "/var/www/html/lib/public/AppFramework/Db/QBMapper.php", "line": 382, "function": "findOneQuery", "class": "OCP\\AppFramework\\Db\\QBMapper", "type": "->", "args": [ { "__class__": "OC\\DB\\QueryBuilder\\QueryBuilder" } ] }, { "file": "/var/www/html/apps-writable/user_migration/lib/Db/UserExportMapper.php", "line": 46, "function": "findEntity", "class": "OCP\\AppFramework\\Db\\QBMapper", "type": "->", "args": [ { "__class__": "OC\\DB\\QueryBuilder\\QueryBuilder" } ] }, { "file": "/var/www/html/apps-writable/user_migration/lib/Service/UserMigrationService.php", "line": 481, "function": "getBySourceUser", "class": "OCA\\UserMigration\\Db\\UserExportMapper", "type": "->", "args": [ "bob" ] }, { "file": "/var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php", "line": 67, "function": "getCurrentJob", "class": "OCA\\UserMigration\\Service\\UserMigrationService", "type": "->", "args": [ { "__class__": "OC\\User\\User" } ] }, { "file": "/var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php", "line": 114, "function": "getCurrentJobData", "class": "OCA\\UserMigration\\Controller\\ApiController", "type": "->", "args": [ { "__class__": "OC\\User\\User" } ] }, { "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php", "line": 205, "function": "status", "class": "OCA\\UserMigration\\Controller\\ApiController", "type": "->", "args": [] }, { "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php", "line": 118, "function": "executeController", "class": "OC\\AppFramework\\Http\\Dispatcher", "type": "->", "args": [ { "__class__": "OCA\\UserMigration\\Controller\\ApiController" }, "status" ] }, { "file": "/var/www/html/lib/private/AppFramework/App.php", "line": 153, "function": "dispatch", "class": "OC\\AppFramework\\Http\\Dispatcher", "type": "->", "args": [ { "__class__": "OCA\\UserMigration\\Controller\\ApiController" }, "status" ] }, { "file": "/var/www/html/lib/private/Route/Router.php", "line": 321, "function": "main", "class": "OC\\AppFramework\\App", "type": "::", "args": [ "OCA\\UserMigration\\Controller\\ApiController", "status", { "__class__": "OC\\AppFramework\\DependencyInjection\\DIContainer" }, { "apiVersion": "1", "_route": "ocs.user_migration.api.status" } ] }, { "file": "/var/www/html/ocs/v1.php", "line": 61, "function": "match", "class": "OC\\Route\\Router", "type": "->", "args": [ "/ocsapp/apps/user_migration/api/v1/status" ] }, { "file": "/var/www/html/ocs/v2.php", "line": 8, "args": [ "/var/www/html/ocs/v1.php" ], "function": "require_once" } ], "File": "/var/www/html/lib/public/AppFramework/Db/QBMapper.php", "Line": 293, "message": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; ", "exception": "{\"class\":\"OCP\\AppFramework\\Db\\MultipleObjectsReturnedException\",\"message\":\"Did not expect more than one result when executing: query \\\"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\\\"; \",\"code\":0,\"file\":\"/var/www/html/lib/public/AppFramework/Db/QBMapper.php:293\",\"trace\":\"#0 /var/www/html/lib/public/AppFramework/Db/QBMapper.php(382): OCP\\AppFramework\\Db\\QBMapper->findOneQuery(Object(OC\\DB\\QueryBuilder\\QueryBuilder))\\n#1 /var/www/html/apps-writable/user_migration/lib/Db/UserExportMapper.php(46): OCP\\AppFramework\\Db\\QBMapper->findEntity(Object(OC\\DB\\QueryBuilder\\QueryBuilder))\\n#2 /var/www/html/apps-writable/user_migration/lib/Service/UserMigrationService.php(481): OCA\\UserMigration\\Db\\UserExportMapper->getBySourceUser('bob')\\n#3 /var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php(67): OCA\\UserMigration\\Service\\UserMigrationService->getCurrentJob(Object(OC\\User\\User))\\n#4 /var/www/html/apps-writable/user_migration/lib/Controller/ApiController.php(114): OCA\\UserMigration\\Controller\\ApiController->getCurrentJobData(Object(OC\\User\\User))\\n#5 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(205): OCA\\UserMigration\\Controller\\ApiController->status()\\n#6 /var/www/html/lib/private/AppFramework/Http/Dispatcher.php(118): OC\\AppFramework\\Http\\Dispatcher->executeController(Object(OCA\\UserMigration\\Controller\\ApiController), 'status')\\n#7 /var/www/html/lib/private/AppFramework/App.php(153): OC\\AppFramework\\Http\\Dispatcher->dispatch(Object(OCA\\UserMigration\\Controller\\ApiController), 'status')\\n#8 /var/www/html/lib/private/Route/Router.php(321): OC\\AppFramework\\App::main('OCA\\\\UserMigrati...', 'status', Object(OC\\AppFramework\\DependencyInjection\\DIContainer), Array)\\n#9 /var/www/html/ocs/v1.php(61): OC\\Route\\Router->match('/ocsapp/apps/us...')\\n#10 /var/www/html/ocs/v2.php(8): require_once('/var/www/html/o...')\\n#11 {main}\"}", "CustomMessage": "Did not expect more than one result when executing: query \"SELECT * FROM `*PREFIX*user_export_jobs` WHERE `source_user` = :dcValue1\"; " } }Actual behaviour
Enforce that there's only one export job by adding a unique constraint or make the service more relaxed.