6.3.2 Remote Executor Matching

Seeing a platform label in Bazel's analyzed action can prove which compatible execution platform Bazel selected. Toolchain-resolution evidence and the action's configured tool inputs establish the selected toolchain separately. Neither can prove that a remote worker with that environment exists, that a backend will route the action to it, or that the worker really provides what the label promises. Matching remote actions is the operational chain that closes those gaps.

A platform label starts a matching contract, not a worker
Trace one admitted action from Bazel intent to an executor that can prove its environment.

GlyphReport begins with its rule-assigned execution group, Bazel's resolved execution platform and toolchain, and stable requirements. REAPI carries opaque properties. A chosen backend interprets exact documented values, maps them to a bounded compatible pool, and an actual executor must fulfill its OS, architecture, tool, runtime, image, and resource promise. Matching needs both uncached placement evidence and visible rejection of incompatible, unknown, or ambiguous requests.

portable: Bazel intent + REAPI transport backend contract: interpretation + bounded routing verified: executor promise + placement
Portable boundary
BAZEL INTENT
GlyphReport selects an execution platform and toolchain
Action-specific group and stable requirements
glyph_report
REAPI TRANSPORT
The request carries opaque Platform properties
Portable carrier, not a property vocabulary
exec_properties: string → string
Backend-owned contract
BOUNDED POOL ROUTING
Backend interprets exact documented values
Versioned mapping to finite compatible pools
known requirement → report pool
ACTUAL EXECUTOR PROMISE
One executor fulfills the requested environment
OS, architecture, tool/runtime, image, resources
environment revision recorded
Accept matching only with both evidence shapes
POSITIVE PLACEMENT
Join action, effective properties, bounded pool, executor identity, and environment revision
Representative uncached remote-only action reaches its intended compatible executor
READINESS REGISTER
Record the verified action contract
Placement evidence closes this matching link
NEGATIVE REJECTION
Incompatible, unknown, or ambiguous requirements reject visibly before execution
No catch-all pool and no local fallback can substitute for this proof
Record a specific property or environment gap
This diagram establishes compatible destinations and fail-closed matching. Queue policy, fairness, capacity, and executor isolation are separate concerns.
Bazel and REAPI preserve portable intent. A particular backend gives properties meaning, routes only to a bounded compatible pool, and must prove an actual executor environment. A green result without placement evidence, or a default pool that accepts bad requests, does not prove matching.

Begin with one action class already admitted by 6.3.1 Making Actions Work Remotely. Its files and tools are declared, its remaining runtime requirements are known, and local fallback is not allowed to hide the test. The job here is to preserve that action's Bazel-side intent as it crosses the protocol and backend boundaries, then obtain evidence that the intended executor actually ran it.

Follow the contract across four boundaries

Keep four statements separate:

  1. Bazel intent: which execution platform and toolchain did Bazel select for this action?
  2. Protocol transport: which properties did Bazel place in the remote action request?
  3. Backend routing: how does this backend interpret those properties and restrict the request to a compatible executor pool?
  4. Executor promise: which concrete OS, architecture, tool/runtime version, image, and resources did the selected executor provide?

The chain is only as strong as its weakest link. If Bazel selects the right platform but the backend ignores an unknown property, intent was not preserved. If routing chooses the intended pool but the worker image is stale, placement was correct while the executor promise was false.

Bazel states intent; it does not provision a worker

Do not confuse the target platform with the execution platform. The target platform describes what the produced artifact is for. The execution platform describes where a build-time action and its tools run. A toolchain can therefore target one platform while its compiler executes on another; its target_compatible_with and exec_compatible_with constraints describe those two directions separately.1

4.6.3 Toolchain Resolution explains how Bazel combines those constraints to select a toolchain and execution platform. At this boundary, the important result is not merely a label: it is a compatible tool, configured for the selected execution environment. A binary built for the client host may fail on a different remote execution platform even when it has the expected filename. Toolchains avoid that host assumption by selecting or supplying a suitable tool.2

One target can also create actions with different requirements. A rule assigns an action to an execution group; Bazel then resolves that group's toolchains and execution platform. Group-qualified execution properties let one action class override the target's default properties.3 That makes “the target's execution platform” too coarse for some investigations: trace the platform, toolchain, and properties of the specific action or execution group. 4.6.5 Execution Groups & Auto Exec Groups covers how rules define and assign those groups; here you consume the resolved result.

The Mini Ruleset report action provides a concrete Bazel-side example. GlyphReport uses the glyph_report execution group, resolves the Glyph toolchain through that group, and requires the report_pool constraint. Its platform declarations give the matching execution platform an execution property.

Run the project's action query to inspect Bazel's resolved action rather than inferring it from the declarations alone:

bazel aquery 'mnemonic("GlyphReport", //examples/basic:module_report)' --output=textproto

In the result, inspect the GlyphReport action's execution platform and effective execution properties. The checked-in captured excerpt shows both execution_platform: "//platforms:report_worker" and the effective Pool=glyph-report property for this action. The runnable Mini Ruleset workspace pins this command in its verification metadata so the observation can be repeated for its Bazel version.

This project proves only Bazel intent. Its platforms inherit the local host so the example remains runnable without an RBE service. It contains no remote scheduler or executor image. The report_worker label therefore does not create a worker, and its property value is not placement evidence.

REAPI transports properties; the backend owns their meaning

A platform's exec_properties is a string-to-string map. Before transport, Bazel computes the effective map: a child platform overrides or removes values inherited from its parent; target-level values override values from the selected platform; and a group-qualified target key such as glyph_report.Pool overrides the corresponding unprefixed key for that group. A target rejects a property qualified with an unknown group, while a platform may carry such group-qualified properties for actions that use the group.1,3

Bazel treats the backend meaning of the resulting names and values as opaque and forwards the effective map through the REAPI Platform field. That is the portable boundary: the protocol can carry named properties with a remote action.

REAPI does not standardize a universal property vocabulary, pool layout, matching algorithm, worker image runtime, or scheduler topology. To understand why a property changes worker selection, the protocol definition points you to the chosen server's scheduler and deployment contract.4

This distinction prevents a common configuration error. A key such as Pool, an image selector, or a resource name may be meaningful to one backend and ignored, rejected, or interpreted differently by another. Even capitalization can be part of that backend contract. Keep vendor property names out of the portable platform vocabulary unless the deployment is deliberately coupled to that backend and the coupling is documented.

Concrete systems demonstrate the variety. One EngFlow embedded-testing example uses a pool property to send test actions to ARM workers.5 A BuildBuddy design organizes executors into pools and incorporates image, OS, CPU, and pool information into its routing key.6 These are useful examples of backend interpretation, not standard REAPI syntax.

Translate to a bounded fleet vocabulary

The ruleset and workload should express stable requirements; the fleet operator should own their translation into deployment inventory. Treat that translation as a versioned table rather than scattered free-form strings:

Bazel-side intentBackend contractBounded destinationExecutor promise
selected execution platform and toolchaindocumented property set and exact supported valuesnamed pool or finite compatible pool setOS/architecture plus tool and runtime/image versions
action- or group-specific resource needdocumented resource classpool with that class availablethe requested resource can be allocated for the action
unsupported or unknown requirementexplicit reject behaviorno default or catch-all placementno executor is falsely advertised as compatible

Prefer a small vocabulary that corresponds to capacity you can inventory and test. A new property value should require an operator-owned mapping, a compatible pool, and an acceptance probe. Otherwise property cardinality grows faster than the fleet can represent, and a nominally precise request becomes ambiguous or unmatchable.

The boundary with scheduling matters here. This article establishes the finite set of destinations that may satisfy a request and requires fail-closed behavior when none does. Queue admission, priority, fairness, dispatch, backpressure, and overload policy continue in 6.3.8 Scheduling Actions on Remote Executors. Capacity sizing for those matchable pools continues in 6.3.12 Remote Execution Capacity.

The actual executor must fulfill the promise

Pool membership is still only a claim. Record the environment version that an executor actually offered: at minimum the relevant OS and architecture, the tool or runtime supplied outside declared action inputs, and the image or other environment revision that defines those surfaces. A tool being present is not enough if its dynamic libraries, SDK, runtime configuration, license access, or kernel capability are incompatible.

This is why heterogeneous workloads are a strong matching probe. A Windows RBE case needed a Windows/x86 platform, a container-image execution property, and a C++ toolchain configured for that container; those were three connected requirements, not three names for the same mechanism.7 An iOS case can start Bazel on Linux while dispatching compilation to macOS workers with Xcode, showing again that the client host and execution environment need not be the same.8

Matching verifies that the selected executor claims and demonstrates the requested environment. It does not yet prove isolation between actions, credentials, cleanup, or safe image evolution. 6.3.9 Remote Executor Environments and Isolation explains those executor lifecycle and runtime controls.

Require positive placement and negative rejection

A compatible success proves only half of matching. For one representative action class, capture and join:

  • the action's assigned execution group, Bazel's selected execution platform, and separate toolchain-resolution/configured-tool evidence;
  • the effective execution properties sent for the action;
  • the backend's interpreted requirement set and selected bounded pool;
  • the operation, executor identity, and environment/image version;
  • an uncached remote result for that attempt, with local fallback excluded and remote cache acceptance disabled or equivalently bypassed for the pinned Bazel/backend version.

The exact placement log, UI, or API is backend-specific. The required evidence shape is not: it must connect the Bazel action to one actual executor whose environment satisfies the promise. Retain evidence equivalent to REAPI's cached_result == false; metadata returned with an earlier cached result does not prove a fresh placement attempt. An endpoint connection, an advertised capability, or a successful build without executor identity is not enough.

Then run negative probes. Change one supported requirement to an incompatible value and send one unknown or ambiguous value. Both requests should reject visibly before incompatible execution. A default pool that accepts either probe has hidden a gap rather than solved it.

think

Classify: The request contains the expected properties, and backend evidence shows that it reached the intended pool. The action then fails because the executor image contains an older runtime than the pool contract specifies. Which boundary passed, which failed, and what observation settles the diagnosis?

Reveal

Protocol transport and backend routing passed: the expected properties reached the intended pool. The executor promise failed. Join the action and executor identity to the actual image or runtime revision, then compare that revision with the version promised for the pool. Changing scheduling priority or the platform label would not repair a stale executor environment.

When either probe fails, write the result back to the readiness register from 6.3.1 Making Actions Work Remotely as a specific property or environment gap. The remediation may change a rule/toolchain requirement or the fleet translation, but it should not broaden every executor image or enable fallback merely to make the action green. 6.3.13 Remote Action Failure Handling defines retry and fallback policy; 6.3.18 Remote Execution Production Readiness later combines matching with the other production qualification gates.

The portable matching contract also becomes an input to 6.3.3 Choosing a Remote Execution Backend. A backend candidate must be able to represent the required properties, route them to bounded compatible capacity, expose placement evidence, and reject unsupported combinations. Product selection begins from that contract, not from a feature checklist.

key takeaway

Bazel resolves the action's assigned execution group's platform and toolchain and computes its effective properties; REAPI carries those properties; a particular backend gives them meaning and restricts the action to a bounded pool; the concrete executor must then provide the promised environment. Neither a platform label nor a vendor property provisions a worker or proves compatibility.

Accept matching only with both kinds of evidence: a representative action is joined to the intended compatible executor and environment, while incompatible, unknown, or ambiguous requirements reject visibly. Record every failure as a specific property or environment gap instead of hiding it with a catch-all pool or local fallback.

Check your understanding · 3 questions

1.Match each part of the remote-matching chain to the evidence or responsibility it represents:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
Bazel intent
Protocol transport
Backend routing
Executor promise

2.Which practices make execution-property routing a dependable matching contract?

Select all that apply

3.True or false: what evidence is needed before accepting an action class as correctly matched?

Choose True or False for each sentence

A result served from the remote cache alone proves that this attempt was placed on a compatible executor.
A representative uncached remote-only attempt should join the action and effective properties to the selected pool, executor identity, and environment revision.
Incompatible, unknown, or ambiguous requirements should reject visibly before incompatible execution.
A successful local fallback can replace a negative rejection probe because the requested action completed.
0 of 3 answered

Footnotes

  1. Platforms and Toolchains Rules — separate execution/target toolchain constraints and opaque forwarding of platform exec_properties 1 2

  2. Adapting Bazel Rules for Remote Execution — host, execution, and target roles plus platform-compatible toolchain binaries

  3. Execution Groups — per-group platform/toolchain resolution and execution-property overrides 1 2

  4. Remote APIs — protocol contracts for caching and remote executionPlatform transport and the boundary between protocol semantics and server-specific matching

  5. Embedded platform testing with Remote Execution — EngFlow-specific pool property routing embedded tests to ARM workers

  6. Lessons From Routing Remote Actions at Scale - Son Luong Ngoc, BuildBuddy — BuildBuddy-specific pools and routing inputs

  7. Bringing Bazel to Windows, then and now — Windows execution platform, container-image property, toolchain, and executor-environment requirements

  8. State of Swift and iOS in Bazel — Linux clients initiating iOS builds on a macOS/Xcode-capable fleet