phacility/phabricator · error · Exception

Unable to build resource interface of type "%s".

Error message

Unable to build resource interface of type "%s".

What it means

DrydockBlueprint::getInterface() delegates to the blueprint implementation (a DrydockBlueprintImplementation subclass) to construct a typed interface object (e.g. 'command' → command interface, 'wcmatches' style host interfaces) for a resource/lease pair. If the implementation returns null for the requested type, the storage layer throws, because downstream code cannot operate on a missing interface. It almost always means the blueprint's concrete class simply does not support that interface type for that resource type.

Source

Thrown at src/applications/drydock/storage/DrydockBlueprint.php:272

    DrydockResource $resource,
    DrydockLease $lease) {
    $this->getImplementation()->destroyLease(
      $this,
      $resource,
      $lease);
    return $this;
  }

  public function getInterface(
    DrydockResource $resource,
    DrydockLease $lease,
    $type) {

    $interface = $this->getImplementation()
      ->getInterface($this, $resource, $lease, $type);

    if (!$interface) {
      throw new Exception(
        pht(
          'Unable to build resource interface of type "%s".',
          $type));
    }

    return $interface;
  }

  public function shouldAllocateSupplementalResource(
    DrydockResource $resource,
    DrydockLease $lease) {
    return $this->getImplementation()->shouldAllocateSupplementalResource(
      $this,
      $resource,
      $lease);
  }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Check the concrete DrydockBlueprintImplementation subclass's getInterface(): add/fill the case for the requested type and return a real interface object
  2. Confirm you are asking the right blueprint: interface availability depends on the blueprint implementation, not just the resource
  3. Verify the type string exactly matches the contract key (e.g. 'command'), no plural/typo
  4. Trace callers of getInterface() on the lease/resource activation path to see which type is requested before the failure

Example fix

// before (custom blueprint implementation)
public function getInterface(
  DrydockBlueprint $blueprint,
  DrydockResource $resource,
  DrydockLease $lease,
  $type) {
  return null; // no handling for $type
}

// after
public function getInterface(
  DrydockBlueprint $blueprint,
  DrydockResource $resource,
  DrydockLease $lease,
  $type) {
  switch ($type) {
    case 'command':
      return id(new DrydockCommandInterface())
        ->setLease($lease)
        ->setResource($resource);
  }
  return null;
}
Defensive patterns

Strategy: try-catch

Type guard

// If your implementation exposes a capability list, check it first:
if (!in_array($type, $blueprint_implementation->getInterfaceTypes(), true)) {
  // request a different blueprint/lease rather than calling getInterface()
}

Try / catch

try {
  $interface = $blueprint->getInterface($resource, $lease, $type);
} catch (Exception $ex) {
  // getInterface() returned null for this type: the blueprint does not
  // support it. Log $type + blueprint class and fail this lease's command
  // with an actionable message; do not retry with the same blueprint/type.
}

Prevention

When it happens

Trigger: Calling `$blueprint->getInterface($resource, $lease, 'command')` on a blueprint implementation whose getInterface() has no case for 'command'; asking for an interface type valid only after the resource is further configured; a third-party blueprint that forgets a default: null return; misspelled interface type string.

Common situations: Writing a custom Drydock blueprint (host blueprint, working-copy blueprint) and testing lease activation; consumers requesting 'command' interfaces from working-copy blueprints that only provide 'command' via their host lease instead; typos like 'commands' vs 'command'.

Related errors


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