phacility/phabricator · error · Exception

Service type "%s" is unrecognized. Valid types are: %s.

Error message

Service type "%s" is unrecognized. Valid types are: %s.

What it means

Thrown by AlmanacServiceEditEngine when a new Almanac service is created through the Conduit API ('almanac.service.edit') and the required 'type' transaction carries a value that is not a registered service type constant. The engine collects the last 'type' transaction from the raw transaction list, looks it up in AlmanacServiceType::getAllServiceTypes(), and rejects unknown keys. The message helpfully lists every valid constant (built-ins: almanac.custom, cluster.database, cluster.repository, drydock.pool).

Source

Thrown at src/applications/almanac/editor/AlmanacServiceEditEngine.php:63

    $type = null;
    foreach ($raw_xactions as $raw_xaction) {
      if ($raw_xaction['type'] !== 'type') {
        continue;
      }

      $type = $raw_xaction['value'];
    }

    if ($type === null) {
      throw new Exception(
        pht(
          'When creating a new Almanac service via the Conduit API, you '.
          'must provide a "type" transaction to select a type.'));
    }

    $map = AlmanacServiceType::getAllServiceTypes();
    if (!isset($map[$type])) {
      throw new Exception(
        pht(
          'Service type "%s" is unrecognized. Valid types are: %s.',
          $type,
          implode(', ', array_keys($map))));
    }

    $this->setServiceType($type);

    return $this->newEditableObject();
  }

  protected function newEditableObjectForDocumentation() {
    $service_type = new AlmanacCustomServiceType();
    $this->setServiceType($service_type->getServiceTypeConstant());
    return $this->newEditableObject();
  }

  protected function newObjectQuery() {

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Read the valid list straight from the error message (or AlmanacServiceType::getAllServiceTypes()) and use one of those exact constants, e.g. "almanac.custom" for a generic service.
  2. Make sure the create request actually includes a transactions entry of type "type" whose value is the constant string, and that no later transaction overwrites it with a bad value (the engine takes the LAST one).
  3. If automating, first call almanac.servicetype.search (or the getAllServiceTypes map in-process) to discover the type constants supported by this install instead of hardcoding them.
  4. When adding a custom service type in an extension, verify the class extends AlmanacServiceType, defines SERVICETYPE (max 64 chars), and is reachable via phutil_map_instances so it appears in the map.

Example fix

// before (Conduit: almanac.service.edit, creating)
$transactions = array(
  array('type' => 'name', 'value' => 'my-service'),
  array('type' => 'type', 'value' => 'custom'),
);

// after
$transactions = array(
  array('type' => 'name', 'value' => 'my-service'),
  array('type' => 'type', 'value' => 'almanac.custom'),
);
Defensive patterns

Strategy: validation

Validate before calling

$valid = array_keys(AlmanacServiceType::getAllServiceTypes());
if (!in_array($my_type, $valid, true)) {
  throw new InvalidArgumentException(
    "Unknown service type '{$my_type}'. Valid: ".implode(', ', $valid));
}

Type guard

function is_valid_almanac_service_type(string $type): bool {
  return isset(AlmanacServiceType::getAllServiceTypes()[$type]);
}

Try / catch

// When calling conduit 'almanac.service.edit' from PHP:
try {
  $result = $client->callMethodSynchronous('almanac.service.edit', $params);
} catch (CommandException $e) {
  // Conduit errors surface with the pht() message; detect type errors and
  // re-fetch the valid list from the message or almanac.servicetype data.
  if (preg_match('/Service type .* is unrecognized/', $e->getMessage())) {
    // fall back to 'almanac.custom' or abort with the valid list
  }
}

Prevention

When it happens

Trigger: Calling almanac.service.edit with object PHID null (create) and transactions [{"type":"type","value":"custom"}] instead of "almanac.custom"; passing a class name like "AlmanacCustomServiceType" instead of the SERVICETYPE constant; passing a cluster type such as "cluster.cache" that does not exist in this install; omitting quoting so the shell/API mangles the dotted constant.

Common situations: Scripts or automation provisioning Almanac services that hardcode a guessed type string; code written against a different Phabricator/Phorge version whose cluster service types differ; copy/paste from UI labels ("Custom Service") instead of the machine constant; custom extensions that register a service type but the Conduit call runs before the class is loadable.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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