{"record":{"id":"a7e3370beddec28a","repo":"phacility/phabricator","slug":"almanac-service-device-property-network-and-nam-a7e337","errorCode":null,"errorMessage":"Almanac service, device, property, network and namespace names must begin and end with a letter or number.","messagePattern":"Almanac service, device, property, network and namespace names must begin and end with a letter or number\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/almanac/util/AlmanacNames.php","lineNumber":57,"sourceCode":"          'may not contain multiple consecutive periods.'));\n    }\n\n    if (preg_match('/\\\\.-|-\\\\./', $name)) {\n      throw new Exception(\n        pht(\n          'Almanac service, device, property, network and namespace names '.\n          'may not contain hyphens adjacent to periods.'));\n    }\n\n    if (preg_match('/--/', $name)) {\n      throw new Exception(\n        pht(\n          'Almanac service, device, property, network and namespace names '.\n          'may not contain multiple consecutive hyphens.'));\n    }\n\n    if (!preg_match('/^[a-z0-9].*[a-z0-9]\\z/', $name)) {\n      throw new Exception(\n        pht(\n          'Almanac service, device, property, network and namespace names '.\n          'must begin and end with a letter or number.'));\n    }\n  }\n\n}\n","sourceCodeStart":39,"sourceCodeEnd":65,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/almanac/util/AlmanacNames.php#L39-L65","documentation":"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.","triggerScenarios":"Names like '-web01', 'web01.', or '.web01' - often the residue of trimming or sanitizing that leaves an edge separator, e.g. trim($value, ' ') leaving '-web-'.","commonSituations":"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'.","solutions":["Trim separators from both ends after sanitizing: $name = trim($name, '-.');","Fix by hand: '-web01' -> 'web01', 'web01.' -> 'web01'.","Run the whole AlmanacNames rule set in your tooling before submitting so you see which rule fails first."],"exampleFix":"// before\n$name = trim(strtolower($raw), ' '); // '-web-01-' keeps edge hyphens -> throws\n\n// after\n$name = trim(preg_replace('/[^a-z0-9.-]+/', '-', strtolower($raw)), '-.'); // 'web-01'","handlingStrategy":"validation","validationCode":"if (!preg_match('/^[a-z0-9].*[a-z0-9]\\z/', $name)) {\n  throw new Exception('Name must begin and end with a letter or number.');\n}\n// Prevent at construction time:\n$name = trim($name, '-.');","typeGuard":"function hasAlphanumericEdges($name) {\n  return (bool)preg_match('/^[a-z0-9].*[a-z0-9]\\z/', $name);\n}","tryCatchPattern":"try {\n  AlmanacNames::validateName($name);\n} catch (Exception $ex) {\n  if (preg_match('/must begin and end with a letter or number/', $ex->getMessage())) {\n    $name = trim($name, '-.'); // fix edges, re-run full rule set\n    AlmanacNames::validateName($name);\n  } else {\n    throw $ex;\n  }\n}","preventionTips":["Always trim '-.' from both ends as the final step of any slugify pipeline.","Reject empty results after trimming instead of submitting them.","Single-character names fail here too (regex needs 2+ chars) - combine with the length rule."],"tags":["almanac","validation","naming","phabricator"],"backgroundTag":"identifier-validation-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}