larksuite/cli · error · ValueError
column labels collide after str() conversion; rename the Dat
Error message
column labels collide after str() conversion; rename the DataFrame columns before packing
What it means
df_to_sheet serializes a pandas DataFrame into the Feishu sheet protocol, which requires string column names. Because every column label is converted with str(), two distinct labels can normalize to the same string (e.g. integer 0 and string '0', or True and 'True'); the packed JSON would then contain duplicate columns and the dtype lookup would silently merge them, so the helper refuses to continue with this ValueError.
Source
Thrown at skills/lark-sheets/scripts/sheets_df.py:34
import pandas as pd
def df_to_sheet(df, name, formats=None):
"""Pack one DataFrame into one entry of a `+table-put --sheets` payload."""
packed = json.loads(df.to_json(orient="split", date_format="iso"))
# The protocol requires string column names. pandas keeps integer labels
# (e.g. the default RangeIndex columns 0/1/2) as JSON numbers, while the
# dtypes dict keys get stringified during JSON serialization — the CLI
# then rejects `columns` ("cannot unmarshal number into … type string")
# and the dtype lookup would miss anyway. Stringify every key once, and
# refuse to continue when that conversion silently merges two columns.
normalized_labels = [str(c) for c in df.columns]
columns = [str(c) for c in packed["columns"]]
if normalized_labels != columns:
columns = normalized_labels
if len(set(columns)) != len(columns):
raise ValueError(
"column labels collide after str() conversion; "
"rename the DataFrame columns before packing"
)
packed["columns"] = columns
dtype_values = list(df.dtypes)
return {
"name": name,
**packed,
"dtypes": {key: str(dtype) for key, dtype in zip(columns, dtype_values)},
**({"formats": {str(k): v for k, v in formats.items()}} if formats else {}),
}
def sheet_to_df(sheet):
"""Restore one `+table-get` sheet dict into a typed DataFrame."""
return pd.DataFrame(sheet["data"], columns=sheet["columns"]).astype(sheet["dtypes"])
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Rename the DataFrame columns so every label is a unique string before calling df_to_sheet, e.g. df.columns = [str(c) for c in df.columns] followed by disambiguating duplicates.
- Audit df.columns for collisions: check that [str(c) for c in df.columns] has the same length as set(...) and fix the offending labels.
- Cast numeric/boolean column labels to unique prefixed strings at data-load time (e.g. 'col_0', 'col_1') so str() conversion cannot merge them.
- If duplicates are intentional data, pivot or transpose so they become row values instead of column labels.
Example fix
// before
df = pd.DataFrame([[1, 2]], columns=[0, "0"])
packed = df_to_sheet(df, "t") # ValueError: labels collide after str()
// after
df = pd.DataFrame([[1, 2]], columns=["count_a", "count_b"])
# or programmatic dedupe:
df.columns = [f"col_{c}" for c in range(df.shape[1])]
packed = df_to_sheet(df, "t") Defensive patterns
Strategy: validation
Validate before calling
labels = [str(c) for c in df.columns]
if len(set(labels)) != len(labels):
dupes = sorted({c for c in labels if labels.count(c) > 1})
raise ValueError(f"columns collide after str(): {dupes}")
# optionally apply proactively:
# df.columns = labels Try / catch
try:
packed = df_to_sheet(df, name)
except ValueError as err:
if "column labels collide" in str(err):
df = df.copy()
df.columns = [f"col_{i}_{c}" for i, c in enumerate(df.columns)]
packed = df_to_sheet(df, name)
else:
raise Prevention
- Always assign plain unique string column labels before packing: df.columns = [str(c) for c in df.columns].
- Never mix numeric and string label types in one DataFrame destined for the sheet protocol.
- Add a df_to_sheet precheck assertion in data-preparation pipelines.
- Avoid default RangeIndex columns; name every column explicitly.
When it happens
Trigger: Calling df_to_sheet(df, name) where df.columns contains labels that map to the same string under str(): mixed int/str labels like 0 and '0', bool True alongside 'True', float 1.0 with '1.0', or any two labels whose str() representations are equal.
Common situations: Building DataFrames from mixed-type sources (JSON payloads, Excel imports with numeric headers, RangeIndex default columns combined with renamed string columns) before packing; merging DataFrames where one side has numeric column labels and the other string labels.
Related errors
- Multiple sheets matched; pass --sheet-id or --sheet-name
- +csv-get truncated the requested range at {source_range}; na
- Invalid column: {col}
- Column index must be >= 1: {index}
- Invalid cell reference: {cell_ref}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/df1ba3affab792e7.
Report an issue: GitHub.