phacility/phabricator · error · Exception

Document already exists!

Error message

Document already exists!

What it means

phriction.create initializes a brand-new wiki document, and document paths are unique. It first queries by the normalized slug (with view and edit capabilities required) and refuses with this error when a document already occupies the path. Nothing is written; the call aborts before any transaction is applied.

Source

Thrown at src/applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php:42

  }

  protected function execute(ConduitAPIRequest $request) {
    $slug = $request->getValue('slug');
    if ($slug === null || !strlen($slug)) {
      throw new Exception(pht('Field "slug" must be non-empty.'));
    }

    $doc = id(new PhrictionDocumentQuery())
      ->setViewer($request->getUser())
      ->withSlugs(array(PhabricatorSlug::normalize($slug)))
      ->requireCapabilities(
        array(
          PhabricatorPolicyCapability::CAN_VIEW,
          PhabricatorPolicyCapability::CAN_EDIT,
        ))
      ->executeOne();
    if ($doc) {
      throw new Exception(pht('Document already exists!'));
    }

    $doc = PhrictionDocument::initializeNewDocument(
      $request->getUser(),
      $slug);

    $xactions = array();
    $xactions[] = id(new PhrictionTransaction())
      ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE)
      ->setNewValue($request->getValue('title'));
    $xactions[] = id(new PhrictionTransaction())
      ->setTransactionType(PhrictionDocumentContentTransaction::TRANSACTIONTYPE)
      ->setNewValue($request->getValue('content'));

    $editor = id(new PhrictionTransactionEditor())
      ->setActor($request->getUser())
      ->setContentSource($request->newContentSource())
      ->setContinueOnNoEffect(true)

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Switch to phriction.edit on the existing slug to update the document
  2. Choose a different slug for the new document
  3. If the existing document was deleted, restore or edit it rather than recreating over the path

Example fix

// before: create fails once the path is taken
$client->callMethodSynchronous('phriction.create', array(
  'slug' => '/runbook/deploy',
  'title' => $title,
  'content' => $content,
));

// after: create once, then edit the existing document
$client->callMethodSynchronous('phriction.edit', array(
  'slug' => '/runbook/deploy',
  'title' => $title,
  'content' => $content,
));
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-check the path, then create only when it is free.
$existing = id(new PhrictionDocumentQuery())
  ->setViewer($viewer)
  ->withSlugs(array(PhabricatorSlug::normalize($slug)))
  ->executeOne();
if ($existing) {
  // route to phriction.edit instead of phriction.create
}

Try / catch

try {
  $result = $client->callMethodSynchronous('phriction.create', $params);
} catch (Exception $ex) {
  if (strpos($ex->getMessage(), 'Document already exists') !== false) {
    $result = $client->callMethodSynchronous('phriction.edit', $params);
  } else {
    throw $ex;
  }
}

Prevention

When it happens

Trigger: Calling phriction.create with a slug whose normalized form matches an existing document, including when the existing document differs only in raw spelling (case, trailing slash, whitespace) that normalizes to the same path.

Common situations: Retry scripts that re-run create after partial failures; multiple tools creating the same page; slug normalization surprises where 'My Page' and 'my-page' collide.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/9368bcf3b966e6cd. Report an issue: GitHub.