{"record":{"id":"aff82266e0bac225","repo":"redis/node-redis","slug":"proxy-no-destination-node","errorCode":null,"errorMessage":"[Proxy] No destination node","messagePattern":"\\[Proxy\\] No destination node","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/test-utils/lib/fault-injector/proxied-fault-injector-cluster.ts","lineNumber":126,"sourceCode":"        `[Proxy] Failed to send SMIGRATING notification: ${migratingResult.error}`\n      );\n    }\n\n    // 2. Simulate maintenance delay\n    await setTimeout(2_000);\n\n    const isNewDestination = params.destination_type === \"new\";\n\n    if (isNewDestination && !nodeWithoutConnections) {\n      throw new Error(`[Proxy] No node with no connections`);\n    }\n\n    const destinationNode = isNewDestination\n      ? nodeWithoutConnections!\n      : nodes.at(-1)!; // Get the last node as the destination\n\n    if (!destinationNode) {\n      throw new Error(`[Proxy] No destination node`);\n    }\n\n    const sMigratedNotification = buildSMigratedNotification([\n      {\n        targetNode: destinationNode,\n        slotRanges: slots,\n      },\n    ]);\n\n    const migratedResult = await this.proxyController.sendToClient(\n      connections[sourceNode.id][0],\n      sMigratedNotification\n    );\n\n    if (!migratedResult.success) {\n      throw new Error(\n        `[Proxy] Failed to send SMIGRATED notification: ${migratedResult.error}`\n      );","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/test-utils/lib/fault-injector/proxied-fault-injector-cluster.ts#L108-L144","documentation":"triggerMigrate selects a destination node (the connectionless node for 'new', or nodes.at(-1) for 'existing') and asserts it with the non-null assertion operator. This runtime guard throws if the chosen destination is undefined — which only happens when the nodes array is empty (getProxyNodes returned no nodes).","triggerScenarios":"getProxyNodes() returns an empty list because the proxy controller reports zero cluster nodes; the cluster has not been discovered yet; the proxy is in a freshly-started state with no nodes registered.","commonSituations":"Calling triggerMigrate before the cluster topology is known to the proxy; proxy started but cluster nodes not yet announced; a prior action tore down the topology.","solutions":["Ensure the proxy has discovered cluster nodes before migrating: await proxyController.getNodes() and check ids is non-empty","Wait for cluster topology convergence before invoking triggerAction","Verify the cluster is actually running and announcing nodes to the proxy"],"exampleFix":"// before — migrate called with no nodes present\nawait proxiedFi.triggerAction({ type: 'migrate', parameters: {...} });\n// Error: [Proxy] No destination node\n\n// after — ensure topology first\nconst nodes = await proxiedFi.getProxyNodes();\nif (nodes.length === 0) throw new Error('cluster not ready');\nawait proxiedFi.triggerAction({ type: 'migrate', parameters: {...} });","handlingStrategy":"validation","validationCode":"async function assertProxyHasNodes(proxiedFi: ProxiedFaultInjectorClientForCluster): Promise<void> {\n  const nodes = await proxiedFi.getProxyNodes();\n  if (nodes.length === 0) {\n    throw new Error('Proxy has no cluster nodes; wait for topology before migrating');\n  }\n}","typeGuard":"function hasProxyNodes(nodes: ProxyNode[]): nodes is [ProxyNode, ...ProxyNode[]] {\n  return nodes.length > 0;\n}","tryCatchPattern":"try {\n  await proxiedFi.triggerAction({ type: 'migrate', parameters: {...} });\n} catch (e) {\n  if (e instanceof Error && /No destination node/.test(e.message)) {\n  }\n  throw e;\n}","preventionTips":["Wait for cluster topology convergence (getProxyNodes non-empty) before migrating","Verify the cluster is running and announcing nodes to the proxy","Guard migrations behind a node-count assertion at the test boundary"],"tags":["fault-injection","proxy","cluster","migration","test-utils","topology"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}