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
- Generate unique fleet IDs per create call (e.g. UUID or name plus suffix)
- Check for the fleet first with getFleet or listFleets and reuse it instead of re-creating
- 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
- Use UUIDs for fleet IDs in scripts that may re-run
- Write bootstrap scripts as get-or-create, never blind create
- Reconcile existing fleets with listFleets before seeding
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
- Fleet ${fleetId} not found
- No pending handoff for issue ${issueId}
- Config file already exists: ${targetPath}. Use --force to ov
- executionId ${run.executionId} already records different evi
- Amendment already resolved: ${amendment.status}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/0e95f57b115f383b.
Report an issue: GitHub.