ruvnet/ruflo · error · Error

Pairing failed for device ${device.deviceId}

Error message

Pairing failed for device ${device.deviceId}

What it means

DeviceLifecycleService.pairDevice calls the device SDK's pair.create() and expects result.paired === true; a structured false result is converted into this exception. It indicates the pairing protocol ran but the device did not confirm pairing — distinct from transport errors, which the SDK would raise itself.

Source

Thrown at v3/@claude-flow/plugin-iot-cognitum/src/domain/services/device-lifecycle-service.ts:116

      endpoint,
      metadata: {},
    };

    this.deps.onDeviceRegistered?.(device);
    return device;
  }

  /**
   * Pair a device using the SDK's pair.create() and promote its trust level.
   */
  async pairDevice(
    device: DeviceAgent,
    clientName: string,
  ): Promise<DeviceAgent> {
    const result = await this.deps.pairDevice(device.deviceId, clientName);

    if (!result.paired) {
      throw new Error(`Pairing failed for device ${device.deviceId}`);
    }

    const oldLevel = device.trustLevel;
    const newLevel =
      device.trustLevel < DeviceTrustLevel.PROVISIONED
        ? DeviceTrustLevel.PROVISIONED
        : device.trustLevel;

    const updated: DeviceAgent = {
      ...device,
      trustLevel: newLevel,
      trustScore: {
        ...device.trustScore,
        overall: this.computeTrustScore(device, 0, 0, true).overall,
        components: {
          ...device.trustScore.components,
          pairingIntegrity: 1.0,
        },

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Verify the device is powered, online, and in pairing mode, then restart the pair flow from the beginning
  2. Check the SDK logs or device endpoint for the underlying refusal reason (timeout, confirmation mismatch)
  3. If an earlier partial pairing left state behind, reset or unregister the device and re-pair

Example fix

// before
const updated = await lifecycle.pairDevice(device, 'gateway-1'); // paired=false -> throws

// after
const probe = await sdkPair(device.deviceId, 'gateway-1');
if (!probe.paired) {
  logger.warn(`pair refused for ${device.deviceId}; keeping trust level ${device.trustLevel}`);
} else {
  const updated = await lifecycle.pairDevice(device, 'gateway-1');
}
Defensive patterns

Strategy: try-catch

Validate before calling

const reachable = await pingDevice(device.endpoint);
if (!reachable) {
  throw new Error(`device ${device.deviceId} unreachable; skip pairing attempt`);
}
return lifecycle.pairDevice(device, clientName);

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try {
    return await lifecycle.pairDevice(device, clientName);
  } catch (e) {
    if (e instanceof Error && e.message.startsWith('Pairing failed for device ')) {
      await sleep(backoff(attempt)); // device may still be in pairing mode
      continue;
    }
    throw e;
  }
}
throw new Error('pairing retries exhausted');

Prevention

When it happens

Trigger: Pairing a device that is offline or at the wrong endpoint; the device's pairing window or confirmation step expired; trust/credential mismatch between coordinator and Seed device; SDK returning paired:false for a busy device.

Common situations: Provisioning lines where the device was power-cycled mid-flow; long delays between initiating and confirming pairing; retrying pairing after a partially completed earlier attempt.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/2cca87bf53afeacc. Report an issue: GitHub.