{"record":{"id":"aa3be9d6aebfe5a9","repo":"dgraph-io/dgraph","slug":"last-coord-not-same-as-first","errorCode":null,"errorMessage":"Last coord not same as first","messagePattern":"Last coord not same as first","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"types/s2.go","lineNumber":138,"sourceCode":"\t}\n\treturn intersects(l1, l2)\n}\n\nfunc convertToGeom(str string) (geom.T, error) {\n\t// validate would ensure that we have a closed loop for all the polygons. We don't support open\n\t// loop polygons.\n\tclosed := func(p *geom.Polygon) error {\n\t\tcoords := p.Coords()\n\t\tif len(coords) == 0 {\n\t\t\treturn errors.Errorf(\"Got empty polygon.\")\n\t\t}\n\t\t// Check that first ring is closed.\n\t\tc := coords[0]\n\t\tl := len(c)\n\t\tif c[0][0] == c[l-1][0] && c[0][1] == c[l-1][1] {\n\t\t\treturn nil\n\t\t}\n\t\treturn errors.Errorf(\"Last coord not same as first\")\n\t}\n\n\tvalidate := func(g geom.T) (geom.T, error) {\n\t\tswitch v := g.(type) {\n\t\tcase *geom.MultiPolygon:\n\t\t\tfor i := range v.NumPolygons() {\n\t\t\t\tif err := closed(v.Polygon(i)); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\tcase *geom.Polygon:\n\t\t\tif err := closed(v); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\treturn g, nil\n\t}\n","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/types/s2.go#L120-L156","documentation":"Thrown by the closed-loop validator in convertToGeom when the first ring of a polygon is not closed — the last coordinate does not repeat the first coordinate. GeoJSON requires linear rings to be closed so the loop can be converted to an S2 loop.","triggerScenarios":"Passing a Polygon (or a ring of a MultiPolygon) whose first ring's last point differs from its first, e.g. [[0,0],[0,5],[5,5],[5,0]] without the closing [0,0].","commonSituations":"Hand-written GeoJSON, geometries exported from tools that emit open rings, or coordinates edited/truncated by upstream code.","solutions":["Close the ring by appending a copy of the first coordinate as the last coordinate","Run a GeoJSON validator on data before ingesting","Programmatically normalize rings (auto-close if c[0] != c[len-1]) prior to calling the API"],"exampleFix":"// before\n[[[0,0],[0,5],[5,5],[5,0]]]\n// after\n[[[0,0],[0,5],[5,5],[5,0],[0,0]]]","handlingStrategy":"validation","validationCode":"ring := poly.Coordinates[0]\nfirst, last := ring[0], ring[len(ring)-1]\nif first[0] != last[0] || first[1] != last[1] {\n    return errors.New(\"linear ring must be closed (first == last)\")\n}","typeGuard":null,"tryCatchPattern":"g, err := types.ConvertToGeom(str)\nif err != nil && strings.Contains(err.Error(), \"Last coord not same as first\") {\n    // auto-close the ring and retry, or reject input\n}","preventionTips":["Auto-close rings during ingestion normalization","Run geojsonhint or equivalent linters on client data","Document the closed-ring requirement for API consumers"],"tags":["geojson","polygon","validation"],"backgroundTag":"unclosed-polygon-ring","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}