ruvnet/ruflo · error · Error

Fleet ${options.fleetId} already exists

Error message

Fleet ${options.fleetId} already exists

What it means

FleetTopologyService.createFleet is an idempotency guard: it looks the fleetId up via repo.findById first and refuses to create a duplicate, protecting the existing fleet (including its device list) from being overwritten by a freshly created empty one.

Source

Thrown at v3/@claude-flow/plugin-iot-cognitum/src/domain/services/fleet-topology-service.ts:59

  retentionDays: 30,
  anomalyDetectionEnabled: true,
  anomalyThreshold: 0.7,
  vectorDimension: 128,
};

const DEFAULT_HEALTH_THRESHOLDS: HealthThresholds = {
  maxOfflineMinutes: 10,
  minUptimeRatio: 0.95,
  maxConsecutiveAnomalies: 3,
  minFirmwareCurrency: 0.8,
};

export class FleetTopologyService {
  constructor(private readonly repo: FleetRepository) {}

  async createFleet(options: CreateFleetOptions): Promise<DeviceFleet> {
    const existing = await this.repo.findById(options.fleetId);
    if (existing) throw new Error(`Fleet ${options.fleetId} already exists`);

    const fleet: DeviceFleet = {
      fleetId: options.fleetId,
      name: options.name,
      description: options.description ?? '',
      zoneId: options.zoneId,
      deviceIds: [],
      topology: options.topology ?? 'star',
      firmwarePolicy: { ...DEFAULT_FIRMWARE_POLICY, ...options.firmwarePolicy },
      telemetryPolicy: { ...DEFAULT_TELEMETRY_POLICY, ...options.telemetryPolicy },
      healthThresholds: { ...DEFAULT_HEALTH_THRESHOLDS, ...options.healthThresholds },
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    await this.repo.save(fleet);
    return fleet;
  }

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Generate unique fleet IDs per create call (e.g. UUID or name plus suffix)
  2. Check for the fleet first with getFleet or listFleets and reuse it instead of re-creating
  3. Catch the error and treat creation as idempotent after verifying the existing fleet matches your spec

Example fix

// before
await fleetService.createFleet({ fleetId: 'default', name: 'Default' }); // second run throws

// after
const existing = await fleetService.getFleet('default').catch(() => null);
if (!existing) {
  await fleetService.createFleet({ fleetId: 'default', name: 'Default' });
}
Defensive patterns

Strategy: validation

Validate before calling

const existing = await fleetService.getFleet(options.fleetId).catch(() => null);
if (existing) {
  return existing; // idempotent: reuse instead of re-create
}
return fleetService.createFleet(options);

Try / catch

try {
  await fleetService.createFleet(options);
} catch (e) {
  if (e instanceof Error && e.message.endsWith('already exists')) {
    const fleet = await fleetService.getFleet(options.fleetId);
    // verify the fleet matches intent before treating as success
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createFleet twice with the same fleetId; re-running bootstrap or seed scripts; two concurrent creators racing with the same deterministic ID.

Common situations: Deterministic fleet IDs ('default', 'factory-floor') colliding across runs; retrying setup after a partially completed run that already saved the fleet; declarative provisioning reapplied without a drift check.

Related errors


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