{"record":{"id":"0e95f57b115f383b","repo":"ruvnet/ruflo","slug":"fleet-options-fleetid-already-exists","errorCode":null,"errorMessage":"Fleet ${options.fleetId} already exists","messagePattern":"Fleet (.+?) already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugin-iot-cognitum/src/domain/services/fleet-topology-service.ts","lineNumber":59,"sourceCode":"  retentionDays: 30,\n  anomalyDetectionEnabled: true,\n  anomalyThreshold: 0.7,\n  vectorDimension: 128,\n};\n\nconst DEFAULT_HEALTH_THRESHOLDS: HealthThresholds = {\n  maxOfflineMinutes: 10,\n  minUptimeRatio: 0.95,\n  maxConsecutiveAnomalies: 3,\n  minFirmwareCurrency: 0.8,\n};\n\nexport class FleetTopologyService {\n  constructor(private readonly repo: FleetRepository) {}\n\n  async createFleet(options: CreateFleetOptions): Promise<DeviceFleet> {\n    const existing = await this.repo.findById(options.fleetId);\n    if (existing) throw new Error(`Fleet ${options.fleetId} already exists`);\n\n    const fleet: DeviceFleet = {\n      fleetId: options.fleetId,\n      name: options.name,\n      description: options.description ?? '',\n      zoneId: options.zoneId,\n      deviceIds: [],\n      topology: options.topology ?? 'star',\n      firmwarePolicy: { ...DEFAULT_FIRMWARE_POLICY, ...options.firmwarePolicy },\n      telemetryPolicy: { ...DEFAULT_TELEMETRY_POLICY, ...options.telemetryPolicy },\n      healthThresholds: { ...DEFAULT_HEALTH_THRESHOLDS, ...options.healthThresholds },\n      createdAt: new Date(),\n      updatedAt: new Date(),\n    };\n\n    await this.repo.save(fleet);\n    return fleet;\n  }","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugin-iot-cognitum/src/domain/services/fleet-topology-service.ts#L41-L77","documentation":"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.","triggerScenarios":"Calling createFleet twice with the same fleetId; re-running bootstrap or seed scripts; two concurrent creators racing with the same deterministic ID.","commonSituations":"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.","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"],"exampleFix":"// before\nawait fleetService.createFleet({ fleetId: 'default', name: 'Default' }); // second run throws\n\n// after\nconst existing = await fleetService.getFleet('default').catch(() => null);\nif (!existing) {\n  await fleetService.createFleet({ fleetId: 'default', name: 'Default' });\n}","handlingStrategy":"validation","validationCode":"const existing = await fleetService.getFleet(options.fleetId).catch(() => null);\nif (existing) {\n  return existing; // idempotent: reuse instead of re-create\n}\nreturn fleetService.createFleet(options);","typeGuard":null,"tryCatchPattern":"try {\n  await fleetService.createFleet(options);\n} catch (e) {\n  if (e instanceof Error && e.message.endsWith('already exists')) {\n    const fleet = await fleetService.getFleet(options.fleetId);\n    // verify the fleet matches intent before treating as success\n  } else throw e;\n}","preventionTips":["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"],"tags":["iot","fleet","duplicate-key","idempotency"],"backgroundTag":"duplicate-entity","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}