Page MenuHomePhorge

AphrontDuplicateKeyQueryException dragging task from milestone column to main board column: Duplicate entry for key 'boardPHID'
Open, Needs TriagePublic

Description

Steps to reproduce (some might be redundant):

  1. Phorge at 03afb97ff20bd5480ecfa0fa809e3b751bd973e8, PHP 8.2.11
  2. Create a project parent
  3. Select Workboard in the left sidebar
  4. Leave New Empty Board and selec the Create Workboard button
  5. See that column Backlog exists
  6. Select in the upper right corner, select Add Column, create additional column foo (might not be needed)
  7. Select Subprojects in the left sidebar
  8. Select Create Milestone in the right sidebar and create milestone jan-mar
  9. Select Create Milestone in the right sidebar and create milestone apr-jun
  10. Go to http://phorge.localhost/maniphest/task/edit/form/default/ , set Tags field to parent and create a new task
  11. In that task, select Add Action...Change Project Tags and change parent to jan-mar
  12. In that task, select Add Action...Change Project Tags and change jan-mar to apr-jun
  13. Go to the workboard of the parent project and try to drag the task from the apr-jun column to the default Backlog column

Expected outcome:
Task is moved from milestone column to parent project column

Actual outcome:

[2023-10-04 21:34:26] EXCEPTION: (AphrontDuplicateKeyQueryException) #1062: Duplicate entry 'PHID-PROJ-yt43plz2cxlidyu4dlia-PHID-PCOL-no7jbin6vngwkrghrmrk...' for key 'boardPHID' at [<phorge>/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:346]
arcanist(head=master, ref.master=35e127da57a8), phorge(head=master, ref.master=03afb97ff20b)
  #0 <#2> AphrontBaseMySQLDatabaseConnection::throwCommonException(integer, string) called at [<phorge>/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:389]
  #1 <#2> AphrontBaseMySQLDatabaseConnection::throwQueryCodeException(integer, string) called at [<phorge>/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:321]
  #2 <#2> AphrontBaseMySQLDatabaseConnection::throwQueryException(mysqli) called at [<phorge>/src/infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:217]
  #3 <#2> AphrontBaseMySQLDatabaseConnection::executeQuery(PhutilQueryString) called at [<phorge>/src/infrastructure/storage/xsprintf/queryfx.php:8]
  #4 <#2> queryfx(AphrontMySQLiDatabaseConnection, string, PhutilQueryString, PhabricatorProjectColumnPosition, array, array) called at [<phorge>/src/infrastructure/storage/connection/AphrontDatabaseConnection.php:58]
  #5 <#2> AphrontDatabaseConnection::query(string, PhutilQueryString, PhabricatorProjectColumnPosition, array, array) called at [<phorge>/src/infrastructure/storage/lisk/LiskDAO.php:1117]
  #6 <#2> LiskDAO::insertRecordIntoDatabase(string) called at [<phorge>/src/infrastructure/storage/lisk/LiskDAO.php:954]
  #7 <#2> LiskDAO::insert() called at [<phorge>/src/infrastructure/storage/lisk/LiskDAO.php:923]
  #8 <#2> LiskDAO::save() called at [<phorge>/src/applications/project/engine/PhabricatorBoardLayoutEngine.php:288]
  #9 <#2> PhabricatorBoardLayoutEngine::applyPositionUpdates() called at [<phorge>/src/applications/maniphest/editor/ManiphestTransactionEditor.php:756]
  #10 <#2> ManiphestTransactionEditor::applyBoardMove(ManiphestTask, array) called at [<phorge>/src/applications/maniphest/editor/ManiphestTransactionEditor.php:89]
  #11 <#2> ManiphestTransactionEditor::applyCustomExternalTransaction(ManiphestTask, ManiphestTransaction) called at [<phorge>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:841]
  #12 <#2> PhabricatorApplicationTransactionEditor::applyExternalEffects(ManiphestTask, ManiphestTransaction) called at [<phorge>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:1409]
  #13 <#2> PhabricatorApplicationTransactionEditor::applyTransactions(ManiphestTask, array) called at [<phorge>/src/applications/project/controller/PhabricatorProjectMoveController.php:140]
  #14 <#2> PhabricatorProjectMoveController::handleRequest(AphrontRequest) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:284]
  #15 phlog(AphrontDuplicateKeyQueryException) called at [<phorge>/src/aphront/handler/PhabricatorDefaultRequestExceptionHandler.php:41]
  #16 PhabricatorDefaultRequestExceptionHandler::handleRequestThrowable(AphrontRequest, AphrontDuplicateKeyQueryException) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:751]
  #17 AphrontApplicationConfiguration::handleThrowable(AphrontDuplicateKeyQueryException) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:296]
  #18 AphrontApplicationConfiguration::processRequest(AphrontRequest, PhutilDeferredLog, AphrontPHPHTTPSink, MultimeterControl) called at [<phorge>/src/aphront/configuration/AphrontApplicationConfiguration.php:203]
  #19 AphrontApplicationConfiguration::runHTTPRequest(AphrontPHPHTTPSink) called at [<phorge>/webroot/index.php:35]

Other information:

Event Timeline

Initially, the task is in the project's default column:

MariaDB [phabricator_project]> SELECT cp.id, p.name AS projectName, cp.boardPHID, c.name AS columnName, cp.columnPHID FROM project_columnposition cp INNER JOIN project_column c ON cp.columnPHID = c.phid INNER JOIN phabricator_project.project p ON cp.boardPHID = p.phid WHERE objectPHID ="PHID-TASK-f6ri2kdpcvtb3yncho2n";
+-----+----------------+--------------------------------+------------+--------------------------------+
| id  | projectName    | boardPHID                      | columnName | columnPHID                     |
+-----+----------------+--------------------------------+------------+--------------------------------+
| 509 | T139396-parent | PHID-PROJ-yt43plz2cxlidyu4dlia | Backloggg  | PHID-PCOL-no7jbin6vngwkrghrmrk |
+-----+----------------+--------------------------------+------------+--------------------------------+

When dragging it on the workboard from the parent project to its "Jan-Mar" milestone,
the code enters buildMoveTransaction() in src/applications/maniphest/editor/ManiphestTransactionEditor.php, realizes that there is a proxy_phid to add (thus the change of the columnPHID in the DB), and there are three transaction types (core:columns and two times core:edge) passed to applyExternalEffects() in src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php.

+-----+----------------+--------------------------------+------------+--------------------------------+
| id  | projectName    | boardPHID                      | columnName | columnPHID                     |
+-----+----------------+--------------------------------+------------+--------------------------------+
| 510 | T139396-parent | PHID-PROJ-yt43plz2cxlidyu4dlia |            | PHID-PCOL-ekr4zowjecvxiwcfrwbr |
+-----+----------------+--------------------------------+------------+--------------------------------+

When using the Add Action dropdown in the single-task view instead,
the code does not enter buildMoveTransaction() at all.
Now only two transaction types (no core:columns; still two core:edge) passed to applyExternalEffects() in src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php, and what was in the DB (see first SQL query in this comment) does not get updated.

Question is how to trigger buildMoveTransaction() also when using the "Add Action" task dropdown, to get the missing core:columns transaction.

For the records, while playing with this I could also reliably reproduce that a task is displayed in two workboard columns simultaneously when dragging back from the second milestone to a non-proxy workboard column which is not the default workboard column.