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
- 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.
- 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).
- 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.
- 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
- Discover type constants programmatically (AlmanacServiceType::getAllServiceTypes() or a servicetype search) instead of hardcoding strings.
- In create pipelines, assert the type transaction is present exactly once with a known constant before submitting.
- Pin automation to the exact Phabricator/Phorge version and re-validate constants after upgrades.
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
- Transaction value when deleting Almanac properties must be a
- Transaction value when setting Almanac properties must be a
- When deleting Almanac properties, each property name must be
- Service "%s" is unrecognized, restricted, or you do not have
- Almanac service, device, property, network and namespace nam
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/f906337e03dc84bb.
Report an issue: GitHub.