phacility/phabricator · error · Exception

Almanac service, device, property, network and namespace nam

Error message

Almanac service, device, property, network and namespace names must begin and end with a letter or number.

What it means

Final rule of AlmanacNames::validateName(): the name must match /^[a-z0-9].*[a-z0-9]\z/, i.e. begin and end with a letter or digit. Leading or trailing hyphens/dots (which the earlier charset rules permit internally) make invalid DNS-label boundaries and are rejected last.

Source

Thrown at src/applications/almanac/util/AlmanacNames.php:57

          'may not contain multiple consecutive periods.'));
    }

    if (preg_match('/\\.-|-\\./', $name)) {
      throw new Exception(
        pht(
          'Almanac service, device, property, network and namespace names '.
          'may not contain hyphens adjacent to periods.'));
    }

    if (preg_match('/--/', $name)) {
      throw new Exception(
        pht(
          'Almanac service, device, property, network and namespace names '.
          'may not contain multiple consecutive hyphens.'));
    }

    if (!preg_match('/^[a-z0-9].*[a-z0-9]\z/', $name)) {
      throw new Exception(
        pht(
          'Almanac service, device, property, network and namespace names '.
          'must begin and end with a letter or number.'));
    }
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Trim separators from both ends after sanitizing: $name = trim($name, '-.');
  2. Fix by hand: '-web01' -> 'web01', 'web01.' -> 'web01'.
  3. Run the whole AlmanacNames rule set in your tooling before submitting so you see which rule fails first.

Example fix

// before
$name = trim(strtolower($raw), ' '); // '-web-01-' keeps edge hyphens -> throws

// after
$name = trim(preg_replace('/[^a-z0-9.-]+/', '-', strtolower($raw)), '-.'); // 'web-01'
Defensive patterns

Strategy: validation

Validate before calling

if (!preg_match('/^[a-z0-9].*[a-z0-9]\z/', $name)) {
  throw new Exception('Name must begin and end with a letter or number.');
}
// Prevent at construction time:
$name = trim($name, '-.');

Type guard

function hasAlphanumericEdges($name) {
  return (bool)preg_match('/^[a-z0-9].*[a-z0-9]\z/', $name);
}

Try / catch

try {
  AlmanacNames::validateName($name);
} catch (Exception $ex) {
  if (preg_match('/must begin and end with a letter or number/', $ex->getMessage())) {
    $name = trim($name, '-.'); // fix edges, re-run full rule set
    AlmanacNames::validateName($name);
  } else {
    throw $ex;
  }
}

Prevention

When it happens

Trigger: Names like '-web01', 'web01.', or '.web01' - often the residue of trimming or sanitizing that leaves an edge separator, e.g. trim($value, ' ') leaving '-web-'.

Common situations: Slugify pipelines that forget to trim separators from the ends; names derived from strings that start or end with separators; splitting 'env.name' and reusing the trailing part '.name'.

Related errors


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