Repository: geopandas/geopandas

Issue:
ENH: Improve error message for attempting to write multiple geometry columns using `to_file`
xref #2565

```python
In [16]: gdf = gpd.GeoDataFrame({"a":[1,2]}, geometry=[Point(1,1), Point(1,2)])

In [17]: gdf['geom2'] = gdf.geometry

In [18]: gdf.to_file("tmp.gpkg")
-----------------------------------
File ...\venv\lib\site-packages\geopandas\io\file.py:596, in infer_schema.<locals>.convert_type(column, in_type)
    594     out_type = types[str(in_type)]
    595 else:
--> 596     out_type = type(np.zeros(1, in_type).item()).__name__
    597 if out_type == "long":
    598     out_type = "int"

TypeError: Cannot interpret '<geopandas.array.GeometryDtype object at 0x0000025FA88908E0>' as a data type

```




Discussion:
@m-richards 
Hi Richards, can I work on this? It might take some time for me to understand the issue but I want to contribute to this because it has a good first issue label (I'm new to OSS community) 
Hey, I can help here too.
Hi @shogohida, thanks for wanting to contribute (and also @DamyanBG, I would suggest however we let shogohida have a go at this first - but you are most welcome to take a look at any of the other open issues, perhaps one of #2357, #2357 would other good places as first contributions as the original contributors there haven't seen those issues through to completion)!

In terms of this specific issue we want improve the experience when a user tries to write a geodataframe with multiple columns - currently we get the cryptic error above. First steps for a solution would be to check something a long the lines of `(gdf.dtypes==geometry).sum()>1` and introduce a specific error message in this case. Happy to give more guidance if you need it though!
@m-richards Thank you, now I will take a look !
@m-richards 
Thanks for your comment! I will try to look into the issue and if I need more help, I will let you know!
@m-richards 
Sorry for the delay. I think the error message should be like "GeoDataFrame has to have single columns" but I'm not sure where the part you indicated (along the lines of `(gdf.dtypes==geometry).sum()>1` ) is....

Can you give me more guidance please?
@shogohida if I'm not mistaken, it's here:
https://github.com/geopandas/geopandas/blob/503330b32fe93f71761a4e611f6063db34711b29/geopandas/io/file.py#L616
Hi @shogohida, the current error (see the example in the first comment of this issue) comes from inside `infer_schema` here:
https://github.com/geopandas/geopandas/blob/174b38c5e379deb7b771102019af42b9b0de7330/geopandas/io/file.py#L552-L555

But given this issue will affect python the pyogrio and fiona io engines we should add a check for multiple geometry columns in the shared `to_file` method, probably between these two if statements:

https://github.com/geopandas/geopandas/blob/174b38c5e379deb7b771102019af42b9b0de7330/geopandas/io/file.py#L537-L545

The code `(gdf.dtypes==geometry).sum()>1` is my suggestion for how we would check if there is more than one geometry column. 

Hope that clarifies a bit.

Resolving patch:
diff --git a/geopandas/io/file.py b/geopandas/io/file.py
--- a/geopandas/io/file.py
+++ b/geopandas/io/file.py
@@ -565,6 +565,15 @@ def _to_file(
             stacklevel=3,
         )
 
+    if (df.dtypes == "geometry").sum() > 1:
+        raise ValueError(
+            "GeoDataFrame contains multiple geometry columns but GeoDataFrame.to_file "
+            "supports only a single geometry column. Use a GeoDataFrame.to_parquet or "
+            "GeoDataFrame.to_feather, drop additional geometry columns or convert them "
+            "to a supported format like a well-known text (WKT) using "
+            "`GeoSeries.to_wkt()`.",
+        )
+
     if mode not in ("w", "a"):
         raise ValueError(f"'mode' should be one of 'w' or 'a', got '{mode}' instead")
 


Test patch:
diff --git a/geopandas/io/tests/test_file.py b/geopandas/io/tests/test_file.py
--- a/geopandas/io/tests/test_file.py
+++ b/geopandas/io/tests/test_file.py
@@ -1134,3 +1134,9 @@ def test_write_read_file(test_file, engine):
     df_json = geopandas.read_file(test_file, engine=engine)
     assert_geodataframe_equal(gdf, df_json, check_crs=True)
     os.remove(os.path.expanduser(test_file))
+
+
+def test_multiple_geom_cols_error(tmpdir, df_nybb):
+    df_nybb["geom2"] = df_nybb.geometry
+    with pytest.raises(ValueError, match="GeoDataFrame contains multiple geometry"):
+        df_nybb.to_file(os.path.join(str(tmpdir), "boros.gpkg"))