{"record":{"id":"b61bc9d6b1506068","repo":"ruvnet/ruflo","slug":"cannot-compute-centroid-of-empty-set","errorCode":null,"errorMessage":"Cannot compute centroid of empty set","messagePattern":"Cannot compute centroid of empty set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/hyperbolic.ts","lineNumber":1000,"sourceCode":"    // Use exponential map from a with half the tangent to b\n    const tangent = this.logMap(a, b);\n    const halfTangent = scale(tangent, 0.5);\n    return this.expMap(a, halfTangent);\n  }\n\n  /**\n   * Computes the Frechet mean (centroid) of multiple points.\n   *\n   * Uses iterative gradient descent on the sum of squared distances.\n   *\n   * @param points - Array of points\n   * @param maxIter - Maximum iterations\n   * @param tol - Convergence tolerance\n   * @returns Frechet mean\n   */\n  centroid(points: number[][], maxIter: number = 100, tol: number = 1e-8): number[] {\n    if (points.length === 0) {\n      throw new Error('Cannot compute centroid of empty set');\n    }\n    if (points.length === 1) {\n      return [...points[0]];\n    }\n\n    // Initialize with Euclidean mean, projected onto manifold\n    let mean = zeros(points[0].length);\n    for (const p of points) {\n      mean = add(mean, p);\n    }\n    mean = this.projectToManifold(scale(mean, 1 / points.length));\n\n    // Iterative refinement\n    for (let iter = 0; iter < maxIter; iter++) {\n      // Compute sum of log maps\n      let gradSum = zeros(points[0].length);\n      for (const p of points) {\n        const logP = this.logMap(mean, p);","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/hyperbolic.ts#L982-L1018","documentation":"HyperbolicSpace.centroid() (hyperbolic.ts:1000) computes the Frechet mean by iterative gradient descent and needs at least one point to define a mean, so an empty array is rejected. A single-element input short-circuits to a copy of that point; two or more points run the iterative loop initialized from the projected Euclidean mean.","triggerScenarios":"centroid([]) called on results of a filter/map that yielded nothing (e.g. clustering a neighborhood with no members); batching points by group where some groups are empty; dependency-graph code computing hyperbolic centroids of empty relation sets.","commonSituations":"Graph analytics where a node has zero neighbors; partitioned datasets with empty partitions; upstream data-quality gaps producing zero embeddings for a category.","solutions":["Skip empty groups before calling centroid: if (group.length === 0) continue","Return a defined fallback point (e.g. origin or the space's default embedding) for empty sets when your algorithm permits","Log which group was empty to trace the upstream filter that produced it"],"exampleFix":"// before\nconst center = space.centroid(group.embeddings); // throws when group has 0 embeddings\n\n// after\nconst center = group.embeddings.length > 0\n  ? space.centroid(group.embeddings)\n  : space.projectToManifold(new Array(dim).fill(0));","handlingStrategy":"validation","validationCode":"function centroidOr(space: HyperbolicSpace, points: number[][], fallback: number[]): number[] {\n  return points.length > 0 ? space.centroid(points) : fallback;\n}\nconst center = centroidOr(space, groupPoints, space.projectToManifold(new Array(dim).fill(0)));","typeGuard":"function isNonEmptyPoints(v: number[][]): v is [number[], ...number[][]] {\n  return Array.isArray(v) && v.length > 0 && v.every(p => Array.isArray(p) && p.length > 0);\n}","tryCatchPattern":"try {\n  mean = space.centroid(points);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Cannot compute centroid of empty set') {\n    mean = space.projectToManifold(new Array(dim).fill(0)); // neutral fallback\n  } else throw err;\n}","preventionTips":["Filter or skip empty groups before computing Frechet means in clustered pipelines","Log empty-group occurrences to catch upstream data gaps early","Define an explicit fallback point (projected origin) for degenerate cases"],"tags":["hyperbolic-geometry","empty-input","centroid","validation"],"backgroundTag":"empty-collection-argument","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}