{"record":{"id":"95f40e4dd9c3863c","repo":"phacility/phabricator","slug":"failed-to-create-a-new-ref-cursor-for-s-of-ty","errorCode":null,"errorMessage":"Failed to create a new ref cursor (for \"%s\", of type \"%s\", in repository \"%s\") because it collided with an existing cursor, but then failed to load that cursor.","messagePattern":"Failed to create a new ref cursor \\(for \"(.+?)\", of type \"(.+?)\", in repository \"(.+?)\"\\) because it collided with an existing cursor, but then failed to load that cursor\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/repository/engine/PhabricatorRepositoryRefEngine.php","lineNumber":643,"sourceCode":"\n    try {\n      return $cursor->save();\n    } catch (AphrontDuplicateKeyQueryException $ex) {\n      // If we raced another daemon to create this position and lost the race,\n      // load the cursor the other daemon created instead.\n    }\n\n    $viewer = $this->getViewer();\n\n    $cursor = id(new PhabricatorRepositoryRefCursorQuery())\n      ->setViewer($viewer)\n      ->withRepositoryPHIDs(array($repository->getPHID()))\n      ->withRefTypes(array($ref_type))\n      ->withRefNames(array($ref_name))\n      ->needPositions(true)\n      ->executeOne();\n    if (!$cursor) {\n      throw new Exception(\n        pht(\n          'Failed to create a new ref cursor (for \"%s\", of type \"%s\", in '.\n          'repository \"%s\") because it collided with an existing cursor, '.\n          'but then failed to load that cursor.',\n          $ref_name,\n          $ref_type,\n          $repository->getDisplayName()));\n    }\n\n    return $cursor;\n  }\n\n  private function saveNewPositions() {\n    $positions = $this->newPositions;\n\n    foreach ($positions as $position) {\n      try {\n        $position->save();","sourceCodeStart":625,"sourceCodeEnd":661,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php#L625-L661","documentation":"Thrown in PhabricatorRepositoryRefEngine when creating a ref cursor: the INSERT hit a duplicate-key exception (AphrontDuplicateKeyQueryException), meaning another daemon won the race to create the same cursor, but the follow-up query that loads the winning cursor by repository PHID, ref type, and ref name returned nothing. So the cursor row exists yet cannot be reloaded, usually because it was deleted between the failed insert and the load, or the query filters (such as the active positions requirement) exclude it.","triggerScenarios":"Two daemons racing to record the same ref update in a cluster; a ref deleted immediately after being created during rapid force-push sequences; cursor cleanup transactions deleting the cursor concurrently; the load filtering out a cursor whose positions were pruned.","commonSituations":"High-frequency force-pushing while multiple ref tasks run; cluster deployments with multiple repository devices; rapid branch create-and-delete cycles in CI automation.","solutions":["Treat as transient first: re-run 'bin/repository refs <repository>' or let the daemon retry the ref update task","If persistent, query the ref cursor table for the named ref to see whether a row actually exists","If rows exist but are not loadable, prune orphaned or broken cursors for that ref and let the engine recreate them","If it recurs constantly in a cluster, reduce ref-update concurrency by binding fewer devices to the repository service"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  $cursor = $engine->updateRefCursor($repository, $ref_type, $ref_name);\n} catch (Exception $ex) {\n  if (preg_match('/failed to load that cursor/', $ex->getMessage())) {\n    // lost the insert race and the winner vanished; retry recreates cleanly\n    $cursor = $engine->updateRefCursor($repository, $ref_type, $ref_name);\n  }\n}","preventionTips":["Expect rare cursor races in clusters; a single retry resolves the normal case","Avoid rapid create-and-delete churn on the same branch name when possible","Keep only the intended devices bound to a repository service to cut ref-update concurrency"],"tags":["phabricator","refs","race-condition","duplicate-key","cursor"],"backgroundTag":"insert-race-condition","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}