{"record":{"id":"b41c28261e8387fd","repo":"toeverything/AFFiNE","slug":"valuenotexists-b41c28","errorCode":"ValueNotExists","errorMessage":"Failed to get start and end points when getting connectable points","messagePattern":"Failed to get start and end points when getting connectable points","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"error","filePath":"blocksuite/affine/gfx/connector/src/connector-manager.ts","lineNumber":569,"sourceCode":"\n  points = removeDulicatePoints(points);\n\n  const sorted = points.map(point => point[0] + ',' + point[1]).sort();\n  sorted.forEach((cur, index) => {\n    if (index === 0) return;\n    if (cur === sorted[index - 1]) {\n      throw new Error('duplicate point');\n    }\n  });\n  const startEnds = [nextStartPoint, lastEndPoint].map(point => {\n    return points.find(\n      item =>\n        almostEqual(item[0], point[0], 0.02) &&\n        almostEqual(item[1], point[1], 0.02)\n    );\n  });\n  if (!startEnds[0] || !startEnds[1]) {\n    throw new BlockSuiteError(\n      BlockSuiteError.ErrorCode.ValueNotExists,\n      'Failed to get start and end points when getting connectable points'\n    );\n  }\n  return { points, nextStartPoint: startEnds[0], lastEndPoint: startEnds[1] };\n}\n\nfunction getDirectPath(startPoint: IVec, endPoint: IVec): IVec[] {\n  if (\n    almostEqual(startPoint[0], endPoint[0], 0.02) ||\n    almostEqual(startPoint[1], endPoint[1], 0.02)\n  ) {\n    return [startPoint, endPoint];\n  } else {\n    const vec = Vec.sub(endPoint, startPoint);\n    const mid: IVec = [startPoint[0], startPoint[1] + vec[1]];\n    return [startPoint, mid, endPoint];\n  }","sourceCodeStart":551,"sourceCodeEnd":587,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/blocksuite/affine/gfx/connector/src/connector-manager.ts#L551-L587","documentation":"While computing connectable points for a connector, the function searches the collected points list for nextStartPoint and lastEndPoint within an almostEqual tolerance of 0.02. If either cannot be found in the list it throws ValueNotExists — the routing geometry is inconsistent and the endpoints are not among the candidate points.","triggerScenarios":"Connector routing where the start/end anchors produce points that, after de-duplication and bound expansion, no longer match any candidate vertex/midpoint within tolerance.","commonSituations":"Zero-size or degenerate element bounds; nested/rotated connectors; floating-point drift between anchor and bound computations; overlapping elements.","solutions":["Verify the connected elements have non-zero bounds before routing.","Loosen or centrally define the almostEqual tolerance if drift is expected.","Guard connectable-points callers and fall back to a direct path when this throws."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function hasNonZeroBound(el: GfxElement): boolean { const b = el.externalBound ?? el.elementBound; return b.w > 0 && b.h > 0; }","typeGuard":null,"tryCatchPattern":"try { return getConnectablePoints(...); } catch (e) { if (e instanceof BlockSuiteError && e.code === BlockSuiteError.ErrorCode.ValueNotExists) { return getDirectPath(start, end); } throw e; }","preventionTips":["Ensure connected elements have non-zero bounds before routing","Fall back to a direct path when endpoint matching fails"],"tags":["connector","gfx","geometry","routing"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}