{"record":{"id":"5468811b0acaad1e","repo":"phacility/phabricator","slug":"this-transcript-has-an-invalid-or-inaccessible-ada","errorCode":null,"errorMessage":"This transcript has an invalid or inaccessible adapter.","messagePattern":"This transcript has an invalid or inaccessible adapter\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/herald/controller/HeraldTranscriptController.php","lineNumber":60,"sourceCode":"    if (!$object_xscript) {\n      $notice = id(new PHUIInfoView())\n        ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)\n        ->setTitle(pht('Old Transcript'))\n        ->appendChild(phutil_tag(\n          'p',\n          array(),\n          pht('Details of this transcript have been garbage collected.')));\n      $content[] = $notice;\n    } else {\n      $map = HeraldAdapter::getEnabledAdapterMap($viewer);\n      $object_type = $object_xscript->getType();\n      if (empty($map[$object_type])) {\n        // TODO: We should filter these out in the Query, but we have to load\n        // the objectTranscript right now, which is potentially enormous. We\n        // should denormalize the object type, or move the data into a separate\n        // table, and then filter this earlier (and thus raise a better error).\n        // For now, just block access so we don't violate policies.\n        throw new Exception(\n          pht('This transcript has an invalid or inaccessible adapter.'));\n      }\n\n      $this->adapter = HeraldAdapter::getAdapterForContentType($object_type);\n\n      $phids = $this->getTranscriptPHIDs($xscript);\n      $phids = array_unique($phids);\n      $phids = array_filter($phids);\n\n      $handles = $this->loadViewerHandles($phids);\n      $this->handles = $handles;\n\n      $warning_panel = $this->buildWarningPanel($xscript);\n      $content[] = $warning_panel;\n\n      $content[] = $this->newContentView($xscript, $view_key);\n    }\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/herald/controller/HeraldTranscriptController.php#L42-L78","documentation":"Thrown by HeraldTranscriptController when rendering a stored Herald transcript whose object type has no enabled adapter for the current viewer. The controller builds the adapter map with HeraldAdapter::getEnabledAdapterMap($viewer); if the transcript's type key is absent (adapter's application uninstalled/disabled, adapter removed from the install, or policy filtering hides it), access is blocked deliberately — the source TODO notes this guard exists so transcript details never leak past application policies.","triggerScenarios":"Opening /herald/transcript/<id>/ after the application that produced the transcript (e.g. Differential, Diffusion, Paste) was uninstalled or disabled in Applications config; loading an old transcript from a since-removed custom adapter; a viewer whose policy filtering removes the adapter from the enabled map.","commonSituations":"Admins uninstall an unused application, then click an old Herald transcript link from a notification or search. Transcripts produced by custom/extension adapters after the extension was disabled or renamed. Upgrades that drop or rename an adapter's content-type key.","solutions":["Re-enable or install the application that owns the transcript's content type (Applications → search the relevant app → Install/Enable), then reload the transcript.","If the adapter is gone permanently (removed upstream or custom), treat the transcript as unviewable and garbage-collect old transcripts (Herald transcript GC) rather than hacking around the guard.","For custom adapters, keep the content-type key stable across renames so old transcripts keep resolving.","Verify the viewing user's policy actually permits the adapter's application — the map is viewer-filtered."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before rendering a transcript, confirm its type is still enabled\n$map = HeraldAdapter::getEnabledAdapterMap($viewer);\nif (!isset($map[$transcript->getType()])) {\n  // render a 'transcript unavailable' notice instead of throwing;\n  // optionally filter these transcripts out of list queries up front\n}","typeGuard":"function transcriptAdapterIsEnabled($viewer, $type) {\n  return isset(HeraldAdapter::getEnabledAdapterMap($viewer)[$type]);\n}","tryCatchPattern":"try {\n  // transcript render path\n} catch (Exception $ex) {\n  if (strpos($ex->getMessage(), 'invalid or inaccessible adapter') !== false) {\n    // show 'details unavailable (application disabled)' page; do not\n    // leak policy-relevant transcript data by working around the guard\n  }\n}","preventionTips":["Keep application content-type keys stable when writing custom adapters so old transcripts keep resolving.","Before uninstalling an application, expect its Herald transcripts to become unviewable — purge them via GC first if you need the history gone cleanly.","Denormalize the object type on transcripts (per the source TODO) so list queries can filter these out earlier."],"tags":["herald","phabricator","php","transcript","adapter","application-uninstalled","policy"],"backgroundTag":"adapter-not-found","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}