{"record":{"id":"31edaacb27f3adf8","repo":"phacility/phabricator","slug":"err-bad-diff","errorCode":"ERR-BAD-DIFF","errorMessage":"ERR-BAD-DIFF","messagePattern":"ERR-BAD-DIFF","errorType":"error_code","errorClass":"ConduitException","httpStatus":null,"severity":"error","filePath":"src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php","lineNumber":66,"sourceCode":"\n    if ($rid) {\n      // Given both a revision and a diff, check that they match.\n      // Given only a revision, find the active diff.\n      $revision = id(new DifferentialRevisionQuery())\n        ->setViewer($request->getUser())\n        ->withIDs(array($rid))\n        ->executeOne();\n      if (!$revision) {\n        throw new ConduitException('ERR-BAD-REVISION');\n      }\n\n      if (!$did) { // did not!\n        $diff = $revision->loadActiveDiff();\n        $did = $diff->getID();\n      } else { // did too!\n        $diff = id(new DifferentialDiff())->load($did);\n        if (!$diff || $diff->getRevisionID() != $rid) {\n          throw new ConduitException('ERR-BAD-DIFF');\n        }\n      }\n    } else if ($did) {\n      // Given only a diff, find the parent revision.\n      $diff = id(new DifferentialDiff())->load($did);\n      if (!$diff) {\n        throw new ConduitException('ERR-BAD-DIFF');\n      }\n      $rid = $diff->getRevisionID();\n    } else {\n      // Given neither, bail.\n      throw new ConduitException('ERR-NEED-DIFF');\n    }\n\n    $file = $request->getValue('filePath');\n    if (!$file) {\n      throw new ConduitException('ERR-NEED-FILE');\n    }","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/differential/conduit/DifferentialCreateInlineConduitAPIMethod.php#L48-L84","documentation":"Thrown by differential.createinline when both revisionID and diffID are supplied. The diff is loaded directly (id(new DifferentialDiff())->load($did), a legacy load with no policy filtering) and must both exist and satisfy diff->getRevisionID() == rid. Failing either check throws ConduitException('ERR-BAD-DIFF').","triggerScenarios":"Passing a diffID that does not exist alongside a valid revisionID, or a diffID that belongs to a different revision (stale cached diff ID, off-by-one when parsing arc output, diff from another working copy).","commonSituations":"Review bots caching diff IDs from earlier runs while the author uploads a new diff; mixing IDs between two revisions edited in parallel; scripts that reuse a diff ID after the revision was updated.","solutions":["Omit diffID when you pass revisionID - the server then uses the revision's active diff, which cannot mismatch","Otherwise re-fetch the current diff ID for the revision (differential.getdiff with revision_id) before calling","Never cache diff IDs across long-running jobs; refresh them per run","When catching ERR-BAD-DIFF, re-resolve the active diff and retry once"],"exampleFix":"// before\n$params = array(\n  'revisionID' => 789,\n  'diffID' => 4210,   // stale: belongs to another revision\n  'filePath' => 'src/app.php',\n);\n\n// after\n$params = array(\n  'revisionID' => 789, // server picks the active diff\n  'filePath' => 'src/app.php',\n);","handlingStrategy":"validation","validationCode":"// Prefer sending only revisionID (server uses the active diff).\n// If you must pin a diff, verify it belongs to the revision first:\n$info = $client->callMethodSynchronous('differential.getdiff',\n  array('diff_id' => (int)$did));\nif ((int)$info['revision_id'] !== (int)$rid) {\n  unset($params['diffID']); // let the server pick the active diff\n}","typeGuard":null,"tryCatchPattern":"try {\n  $client->callMethodSynchronous('differential.createinline', $params);\n} catch (ConduitClientException $ex) {\n  if ($ex->getErrorCode() === 'ERR-BAD-DIFF') {\n    unset($params['diffID']); // retry once with the active diff\n    $client->callMethodSynchronous('differential.createinline', $params);\n  } else {\n    throw $ex;\n  }\n}","preventionTips":["Send revisionID alone unless a specific historical diff is required","Never cache diff IDs across revision updates","When both IDs are sent, treat a mismatch as stale local state and re-resolve"],"tags":["phabricator","conduit","differential","diff","id-mismatch"],"backgroundTag":"entity-mismatch","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}