[{"data":1,"prerenderedAt":1740},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars":1710,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars":1719,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars":1724,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars":1725},{"id":4,"title":5,"body":6,"dateModified":1676,"datePublished":1676,"description":1677,"extension":1678,"faq":1679,"keyword":1688,"kind":1689,"meta":1690,"navigation":121,"path":1699,"seo":1700,"slug":1703,"stem":1704,"topics":1705,"type":1708,"__hash__":1709},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars\u002Findex.md","Fix Schema and Type Errors When Reading Excel with Polars",{"type":7,"value":8,"toc":1663},"minimark",[9,36,41,69,86,90,93,196,233,431,435,438,619,629,633,647,787,817,821,828,1062,1103,1233,1237,1240,1381,1411,1516,1520,1530,1534,1573,1577,1598,1602,1608,1614,1620,1626,1630,1659],[10,11,12,13,17,18,21,22,25,26,29,30,35],"p",{},"Reading a workbook with ",[14,15,16],"code",{},"pl.read_excel"," is quick and usually just works — which is exactly why its one dangerous behaviour goes unnoticed. Polars, through the calamine engine, decides each column's type from the first rows and then converts every cell to that type. A cell that does not fit — a product code ",[14,19,20],{},"A-77"," in a column of numbers, ",[14,23,24],{},"n\u002Fa"," in an amount column, a date typed as text — is not reported as an error. It becomes ",[14,27,28],{},"null",", and the row loses its value silently. This page reproduces that with a small but realistic sheet, shows how to detect it, and fixes it properly: control the inference, read awkward columns as text, cast them yourself with a list of everything that failed, and deal with blank and duplicate headers and empty sheets along the way. It belongs to ",[31,32,34],"a",{"href":33},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002F","Reading Excel with Polars and Arrow",".",[37,38,40],"h2",{"id":39},"prerequisites","Prerequisites",[42,43,48],"pre",{"className":44,"code":45,"language":46,"meta":47,"style":47},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install polars fastexcel\n","bash","",[14,49,50],{"__ignoreMap":47},[51,52,55,59,63,66],"span",{"class":53,"line":54},"line",1,[51,56,58],{"class":57},"sMTad","pip",[51,60,62],{"class":61},"srMev"," install",[51,64,65],{"class":61}," polars",[51,67,68],{"class":61}," fastexcel\n",[10,70,71,74,75,77,78,81,82,85],{},[14,72,73],{},"mixed.xlsx"," has 150 well-behaved rows followed by one awkward row: a text product code, the text ",[14,76,24],{}," in the Amount column, a date typed as text in day\u002Fmonth\u002Fyear order, and a fractional quantity. Its header has a blank column name and a duplicated ",[14,79,80],{},"Qty",". ",[14,83,84],{},"empty.xlsx"," contains a sheet with nothing on it. The examples were run with Polars 1.44 and the default calamine engine.",[37,87,89],{"id":88},"step-1-reproduce-the-silent-nulls","Step 1 — Reproduce the silent nulls",[10,91,92],{},"Read the sheet with defaults and look at the schema and the last row:",[42,94,98],{"className":95,"code":96,"language":97,"meta":47,"style":47},"language-python shiki shiki-themes github-light github-dark-high-contrast","import polars as pl\n\ndf = pl.read_excel(\"mixed.xlsx\")\nprint(df.schema)\nprint(df.tail(2))\nprint(\"nulls per column:\", df.null_count().row(0, named=True))\n","python",[14,99,100,116,123,141,151,165],{"__ignoreMap":47},[51,101,102,106,110,113],{"class":53,"line":54},[51,103,105],{"class":104},"s-kum","import",[51,107,109],{"class":108},"skGVy"," polars ",[51,111,112],{"class":104},"as",[51,114,115],{"class":108}," pl\n",[51,117,119],{"class":53,"line":118},2,[51,120,122],{"emptyLinePlaceholder":121},true,"\n",[51,124,126,129,132,135,138],{"class":53,"line":125},3,[51,127,128],{"class":108},"df ",[51,130,131],{"class":104},"=",[51,133,134],{"class":108}," pl.read_excel(",[51,136,137],{"class":61},"\"mixed.xlsx\"",[51,139,140],{"class":108},")\n",[51,142,144,148],{"class":53,"line":143},4,[51,145,147],{"class":146},"sP0c6","print",[51,149,150],{"class":108},"(df.schema)\n",[51,152,154,156,159,162],{"class":53,"line":153},5,[51,155,147],{"class":146},[51,157,158],{"class":108},"(df.tail(",[51,160,161],{"class":146},"2",[51,163,164],{"class":108},"))\n",[51,166,168,170,173,176,179,182,185,189,191,194],{"class":53,"line":167},6,[51,169,147],{"class":146},[51,171,172],{"class":108},"(",[51,174,175],{"class":61},"\"nulls per column:\"",[51,177,178],{"class":108},", df.null_count().row(",[51,180,181],{"class":146},"0",[51,183,184],{"class":108},", ",[51,186,188],{"class":187},"sa561","named",[51,190,131],{"class":104},[51,192,193],{"class":146},"True",[51,195,164],{"class":108},[10,197,198,199,202,203,184,206,202,209,212,213,202,216,218,219,81,221,184,223,212,225,228,229,232],{},"The read succeeds without a warning. Polars inferred ",[14,200,201],{},"Code"," as ",[14,204,205],{},"Int64",[14,207,208],{},"Amount",[14,210,211],{},"Float64"," and ",[14,214,215],{},"Date",[14,217,215],{}," from the first rows — and in the last row all three are ",[14,220,28],{},[14,222,20],{},[14,224,24],{},[14,226,227],{},"31\u002F05\u002F2026"," were simply dropped because they did not fit. The fractional ",[14,230,231],{},"3.5"," survived because Qty was inferred as a float. Nothing in the output says three values were lost; only counting nulls reveals it, and only if you know there should not be any. In a large file, this is how a handful of rows quietly fall out of a total.",[234,235,243,244,243,248,243,252,243,259,243,268,243,272,243,279,243,283,243,287,243,291,243,295,243,299,243,303,243,307,243,312,243,314,243,317,243,319,243,321,243,323,243,325,243,327,243,329,243,332,243,335,243,337,243,340,243,342,243,344,243,346,243,348,243,350,243,352,243,355,243,359,243,362,243,365,243,369,243,372,243,375,243,378,243,384,243,386,243,388,243,392,243,396,243,402,243,406,243,412,243,417,243,425],"svg",{"viewBox":236,"role":237,"ariaLabelledBy":238,"xmlns":241,"style":242},"20 0 719 136","img",[239,240],"plt-null-t","plt-null-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:719px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[245,246,247],"title",{"id":239},"What the default read does to an awkward row",[249,250,251],"desc",{"id":240},"The last row holds the code A-77, the text n\u002Fa, the text date 31\u002F05\u002F2026 and the quantity 3.5. Columns were inferred from the first rows as integer, float and date, so the code, the amount and the date become null without any warning. The quantity survives because the column was inferred as a float.",[253,254],"rect",{"x":255,"y":181,"width":256,"height":257,"fill":258},"20","719","136","#ffffff",[253,260],{"x":261,"y":262,"width":263,"height":264,"rx":181,"fill":265,"stroke":266,"style":267},"36.5","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[253,269],{"x":270,"y":262,"width":271,"height":264,"rx":181,"fill":265,"stroke":266,"style":267},"68.5","52.4",[273,274,278],"text",{"x":275,"y":276,"style":277},"94.8","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[253,280],{"x":281,"y":262,"width":282,"height":264,"rx":181,"fill":265,"stroke":266,"style":267},"121.0","66.8",[273,284,286],{"x":285,"y":276,"style":277},"154.4","B",[253,288],{"x":289,"y":262,"width":290,"height":264,"rx":181,"fill":265,"stroke":266,"style":267},"187.8","87.2",[273,292,294],{"x":293,"y":276,"style":277},"231.4","C",[253,296],{"x":297,"y":262,"width":298,"height":264,"rx":181,"fill":265,"stroke":266,"style":267},"275.0","44.0",[273,300,302],{"x":301,"y":276,"style":277},"297.0","D",[253,304],{"x":261,"y":305,"width":263,"height":306,"rx":181,"fill":265,"stroke":266,"style":267},"64.0","28.0",[273,308,311],{"x":309,"y":310,"style":277},"52.5","83.0","1",[253,313],{"x":270,"y":305,"width":271,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,315,201],{"x":275,"y":310,"style":316},"font-size:10.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[253,318],{"x":281,"y":305,"width":282,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,320,208],{"x":285,"y":310,"style":316},[253,322],{"x":289,"y":305,"width":290,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,324,215],{"x":293,"y":310,"style":316},[253,326],{"x":297,"y":305,"width":298,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,328,80],{"x":301,"y":310,"style":316},[253,330],{"x":261,"y":331,"width":263,"height":306,"rx":181,"fill":265,"stroke":266,"style":267},"92.0",[273,333,161],{"x":309,"y":334,"style":277},"111.0",[253,336],{"x":270,"y":331,"width":271,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,338,20],{"x":275,"y":334,"style":339},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[253,341],{"x":281,"y":331,"width":282,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,343,24],{"x":285,"y":334,"style":339},[253,345],{"x":289,"y":331,"width":290,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,347,227],{"x":293,"y":334,"style":339},[253,349],{"x":297,"y":331,"width":298,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},[273,351,231],{"x":301,"y":334,"style":339},[253,353],{"x":354,"y":262,"width":271,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},"511.2",[273,356,201],{"x":357,"y":358,"style":316},"537.4","59.0",[253,360],{"x":361,"y":262,"width":282,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},"563.7",[273,363,208],{"x":364,"y":358,"style":316},"597.1",[253,366],{"x":367,"y":262,"width":368,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},"630.5","49.0",[273,370,215],{"x":371,"y":358,"style":316},"655.0",[253,373],{"x":374,"y":262,"width":298,"height":306,"rx":181,"fill":258,"stroke":266,"style":267},"679.5",[273,376,80],{"x":377,"y":358,"style":316},"701.5",[253,379],{"x":354,"y":380,"width":271,"height":306,"rx":181,"fill":381,"stroke":382,"style":383},"68.0","#fce9e9","var(--danger,#dc2626)","stroke-width:1.5px",[253,385],{"x":361,"y":380,"width":282,"height":306,"rx":181,"fill":381,"stroke":382,"style":383},[253,387],{"x":367,"y":380,"width":368,"height":306,"rx":181,"fill":381,"stroke":382,"style":383},[253,389],{"x":374,"y":380,"width":298,"height":306,"rx":181,"fill":390,"stroke":391,"style":383},"#d9f4f1","var(--teal,#0f9488)",[273,393,231],{"x":377,"y":394,"style":395},"87.0","font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[273,397,401],{"x":398,"y":399,"style":400},"177.8","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","in the sheet",[273,403,405],{"x":404,"y":399,"style":400},"617.3","in the DataFrame",[53,407],{"x1":408,"y1":380,"x2":409,"y2":380,"stroke":410,"style":411},"329.0","497.2","var(--brand,#5b5cf0)","stroke-width:2px",[413,414],"polygon",{"points":415,"fill":416},"501.2,68.0 492.2,73.0 492.2,63.0","#5b5cf0",[253,418],{"x":419,"y":420,"width":421,"height":422,"rx":423,"fill":258,"stroke":266,"style":424},"354.2","35.0","121.8","22.0","11","stroke-width:1.2px",[273,426,430],{"x":427,"y":428,"style":429},"415.1","50.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","inferred types",[37,432,434],{"id":433},"step-2-detect-silent-losses-on-every-read","Step 2 — Detect silent losses on every read",[10,436,437],{},"The reliable way to catch this is to read the same columns twice — once as plain text, once with the types you want — and compare where values exist:",[42,439,441],{"className":95,"code":440,"language":97,"meta":47,"style":47},"raw = pl.read_excel(\"mixed.xlsx\", infer_schema_length=0)       # every column as String\nprint({c: str(t) for c, t in raw.schema.items()})\n\ndef lost_values(raw, typed):\n    report = []\n    for col in typed.columns:\n        mask = raw[col].is_not_null() & typed[col].is_null()\n        for idx in mask.arg_true().to_list():\n            report.append({\"row\": idx + 2, \"column\": col, \"value\": raw[col][idx]})\n    return pl.DataFrame(report)\n\nprint(lost_values(raw, df))\n",[14,442,443,470,495,499,511,521,534,551,565,597,606,611],{"__ignoreMap":47},[51,444,445,448,450,452,454,456,459,461,463,466],{"class":53,"line":54},[51,446,447],{"class":108},"raw ",[51,449,131],{"class":104},[51,451,134],{"class":108},[51,453,137],{"class":61},[51,455,184],{"class":108},[51,457,458],{"class":187},"infer_schema_length",[51,460,131],{"class":104},[51,462,181],{"class":146},[51,464,465],{"class":108},")       ",[51,467,469],{"class":468},"s-wDw","# every column as String\n",[51,471,472,474,477,480,483,486,489,492],{"class":53,"line":118},[51,473,147],{"class":146},[51,475,476],{"class":108},"({c: ",[51,478,479],{"class":146},"str",[51,481,482],{"class":108},"(t) ",[51,484,485],{"class":104},"for",[51,487,488],{"class":108}," c, t ",[51,490,491],{"class":104},"in",[51,493,494],{"class":108}," raw.schema.items()})\n",[51,496,497],{"class":53,"line":125},[51,498,122],{"emptyLinePlaceholder":121},[51,500,501,504,508],{"class":53,"line":143},[51,502,503],{"class":104},"def",[51,505,507],{"class":506},"s_Opv"," lost_values",[51,509,510],{"class":108},"(raw, typed):\n",[51,512,513,516,518],{"class":53,"line":153},[51,514,515],{"class":108},"    report ",[51,517,131],{"class":104},[51,519,520],{"class":108}," []\n",[51,522,523,526,529,531],{"class":53,"line":167},[51,524,525],{"class":104},"    for",[51,527,528],{"class":108}," col ",[51,530,491],{"class":104},[51,532,533],{"class":108}," typed.columns:\n",[51,535,537,540,542,545,548],{"class":53,"line":536},7,[51,538,539],{"class":108},"        mask ",[51,541,131],{"class":104},[51,543,544],{"class":108}," raw[col].is_not_null() ",[51,546,547],{"class":104},"&",[51,549,550],{"class":108}," typed[col].is_null()\n",[51,552,554,557,560,562],{"class":53,"line":553},8,[51,555,556],{"class":104},"        for",[51,558,559],{"class":108}," idx ",[51,561,491],{"class":104},[51,563,564],{"class":108}," mask.arg_true().to_list():\n",[51,566,568,571,574,577,580,583,585,588,591,594],{"class":53,"line":567},9,[51,569,570],{"class":108},"            report.append({",[51,572,573],{"class":61},"\"row\"",[51,575,576],{"class":108},": idx ",[51,578,579],{"class":104},"+",[51,581,582],{"class":146}," 2",[51,584,184],{"class":108},[51,586,587],{"class":61},"\"column\"",[51,589,590],{"class":108},": col, ",[51,592,593],{"class":61},"\"value\"",[51,595,596],{"class":108},": raw[col][idx]})\n",[51,598,600,603],{"class":53,"line":599},10,[51,601,602],{"class":104},"    return",[51,604,605],{"class":108}," pl.DataFrame(report)\n",[51,607,609],{"class":53,"line":608},11,[51,610,122],{"emptyLinePlaceholder":121},[51,612,614,616],{"class":53,"line":613},12,[51,615,147],{"class":146},[51,617,618],{"class":108},"(lost_values(raw, df))\n",[10,620,621,624,625,628],{},[14,622,623],{},"infer_schema_length=0"," tells Polars not to infer at all and to read every column as ",[14,626,627],{},"String",", so nothing can be lost. Any cell that has text in the raw read but is null in the typed read was dropped by the conversion; the report lists its Excel row (data rows start at row 2) and the original value. This check costs a second read, which with calamine is cheap, and it turns a silent loss into a list someone can act on. Running it in the pipeline's tests or as a guard before loading data elsewhere is a good habit.",[37,630,632],{"id":631},"step-3-control-the-inference","Step 3 — Control the inference",[10,634,635,636,638,639,642,643,646],{},"Two parameters change how types are chosen. ",[14,637,458],{}," sets how many rows Polars samples; ",[14,640,641],{},"None"," means all of them. ",[14,644,645],{},"schema_overrides"," fixes the type of named columns:",[42,648,650],{"className":95,"code":649,"language":97,"meta":47,"style":47},"whole = pl.read_excel(\"mixed.xlsx\", infer_schema_length=None)\nprint(\"infer from all rows:\", {c: str(t) for c, t in whole.schema.items() if c in (\"Code\", \"Amount\", \"Date\")})\n\npinned = pl.read_excel(\"mixed.xlsx\", schema_overrides={\"Code\": pl.String, \"Amount\": pl.String, \"Date\": pl.String})\nprint(pinned.select(\"Code\", \"Amount\", \"Date\").tail(2))\n",[14,651,652,673,725,729,763],{"__ignoreMap":47},[51,653,654,657,659,661,663,665,667,669,671],{"class":53,"line":54},[51,655,656],{"class":108},"whole ",[51,658,131],{"class":104},[51,660,134],{"class":108},[51,662,137],{"class":61},[51,664,184],{"class":108},[51,666,458],{"class":187},[51,668,131],{"class":104},[51,670,641],{"class":146},[51,672,140],{"class":108},[51,674,675,677,679,682,685,687,689,691,693,695,698,701,704,706,709,712,714,717,719,722],{"class":53,"line":118},[51,676,147],{"class":146},[51,678,172],{"class":108},[51,680,681],{"class":61},"\"infer from all rows:\"",[51,683,684],{"class":108},", {c: ",[51,686,479],{"class":146},[51,688,482],{"class":108},[51,690,485],{"class":104},[51,692,488],{"class":108},[51,694,491],{"class":104},[51,696,697],{"class":108}," whole.schema.items() ",[51,699,700],{"class":104},"if",[51,702,703],{"class":108}," c ",[51,705,491],{"class":104},[51,707,708],{"class":108}," (",[51,710,711],{"class":61},"\"Code\"",[51,713,184],{"class":108},[51,715,716],{"class":61},"\"Amount\"",[51,718,184],{"class":108},[51,720,721],{"class":61},"\"Date\"",[51,723,724],{"class":108},")})\n",[51,726,727],{"class":53,"line":125},[51,728,122],{"emptyLinePlaceholder":121},[51,730,731,734,736,738,740,742,744,746,749,751,754,756,758,760],{"class":53,"line":143},[51,732,733],{"class":108},"pinned ",[51,735,131],{"class":104},[51,737,134],{"class":108},[51,739,137],{"class":61},[51,741,184],{"class":108},[51,743,645],{"class":187},[51,745,131],{"class":104},[51,747,748],{"class":108},"{",[51,750,711],{"class":61},[51,752,753],{"class":108},": pl.String, ",[51,755,716],{"class":61},[51,757,753],{"class":108},[51,759,721],{"class":61},[51,761,762],{"class":108},": pl.String})\n",[51,764,765,767,770,772,774,776,778,780,783,785],{"class":53,"line":153},[51,766,147],{"class":146},[51,768,769],{"class":108},"(pinned.select(",[51,771,711],{"class":61},[51,773,184],{"class":108},[51,775,716],{"class":61},[51,777,184],{"class":108},[51,779,721],{"class":61},[51,781,782],{"class":108},").tail(",[51,784,161],{"class":146},[51,786,164],{"class":108},[10,788,789,790,212,792,794,795,797,798,800,801,803,804,806,807,809,810,813,814,816],{},"Inferring from every row makes ",[14,791,201],{},[14,793,215],{}," strings — the presence of ",[14,796,20],{}," and the text date means no stricter type fits — but ",[14,799,208],{}," still comes out as ",[14,802,211],{}," with ",[14,805,24],{}," as null, because one text value among 150 numbers is treated as not fitting rather than as a reason to give up on numbers. Pinning the awkward columns to ",[14,808,627],{}," keeps every value as written; note that real dates read as text arrive in the ",[14,811,812],{},"2026-05-30 00:00:00"," form, while the typed-in date keeps its ",[14,815,227],{}," form. Neither parameter makes the data clean; they decide whether problems are dropped or kept for you to deal with. Keeping them is almost always the right choice.",[37,818,820],{"id":819},"step-4-cast-yourself-and-report-what-fails","Step 4 — Cast yourself, and report what fails",[10,822,823,824,827],{},"With the awkward columns read as text, cast them explicitly with ",[14,825,826],{},"strict=False"," and collect the values that could not be converted:",[42,829,831],{"className":95,"code":830,"language":97,"meta":47,"style":47},"clean = pinned.with_columns(\n    pl.col(\"Code\").str.strip_chars().alias(\"Code\"),\n    pl.col(\"Amount\").cast(pl.Float64, strict=False).alias(\"Amount num\"),\n    pl.coalesce(\n        pl.col(\"Date\").str.to_date(\"%Y-%m-%d %H:%M:%S\", strict=False),\n        pl.col(\"Date\").str.to_date(\"%d\u002F%m\u002F%Y\", strict=False),\n    ).alias(\"Date parsed\"),\n)\nfailed = clean.filter(\n    (pl.col(\"Amount\").is_not_null() & pl.col(\"Amount num\").is_null())\n    | (pl.col(\"Date\").is_not_null() & pl.col(\"Date parsed\").is_null())\n).select(\"Code\", \"Amount\", \"Date\")\nprint(clean.select(\"Code\", \"Amount num\", \"Date parsed\").tail(2))\nprint(\"could not convert:\", failed.to_dicts())\n",[14,832,833,843,858,883,888,918,944,954,958,968,988,1008,1025,1049],{"__ignoreMap":47},[51,834,835,838,840],{"class":53,"line":54},[51,836,837],{"class":108},"clean ",[51,839,131],{"class":104},[51,841,842],{"class":108}," pinned.with_columns(\n",[51,844,845,848,850,853,855],{"class":53,"line":118},[51,846,847],{"class":108},"    pl.col(",[51,849,711],{"class":61},[51,851,852],{"class":108},").str.strip_chars().alias(",[51,854,711],{"class":61},[51,856,857],{"class":108},"),\n",[51,859,860,862,864,867,870,872,875,878,881],{"class":53,"line":125},[51,861,847],{"class":108},[51,863,716],{"class":61},[51,865,866],{"class":108},").cast(pl.Float64, ",[51,868,869],{"class":187},"strict",[51,871,131],{"class":104},[51,873,874],{"class":146},"False",[51,876,877],{"class":108},").alias(",[51,879,880],{"class":61},"\"Amount num\"",[51,882,857],{"class":108},[51,884,885],{"class":53,"line":143},[51,886,887],{"class":108},"    pl.coalesce(\n",[51,889,890,893,895,898,901,905,908,910,912,914,916],{"class":53,"line":153},[51,891,892],{"class":108},"        pl.col(",[51,894,721],{"class":61},[51,896,897],{"class":108},").str.to_date(",[51,899,900],{"class":61},"\"%Y-%m-",[51,902,904],{"class":903},"sSjpA","%d",[51,906,907],{"class":61}," %H:%M:%S\"",[51,909,184],{"class":108},[51,911,869],{"class":187},[51,913,131],{"class":104},[51,915,874],{"class":146},[51,917,857],{"class":108},[51,919,920,922,924,926,929,931,934,936,938,940,942],{"class":53,"line":167},[51,921,892],{"class":108},[51,923,721],{"class":61},[51,925,897],{"class":108},[51,927,928],{"class":61},"\"",[51,930,904],{"class":903},[51,932,933],{"class":61},"\u002F%m\u002F%Y\"",[51,935,184],{"class":108},[51,937,869],{"class":187},[51,939,131],{"class":104},[51,941,874],{"class":146},[51,943,857],{"class":108},[51,945,946,949,952],{"class":53,"line":536},[51,947,948],{"class":108},"    ).alias(",[51,950,951],{"class":61},"\"Date parsed\"",[51,953,857],{"class":108},[51,955,956],{"class":53,"line":553},[51,957,140],{"class":108},[51,959,960,963,965],{"class":53,"line":567},[51,961,962],{"class":108},"failed ",[51,964,131],{"class":104},[51,966,967],{"class":108}," clean.filter(\n",[51,969,970,973,975,978,980,983,985],{"class":53,"line":599},[51,971,972],{"class":108},"    (pl.col(",[51,974,716],{"class":61},[51,976,977],{"class":108},").is_not_null() ",[51,979,547],{"class":104},[51,981,982],{"class":108}," pl.col(",[51,984,880],{"class":61},[51,986,987],{"class":108},").is_null())\n",[51,989,990,993,996,998,1000,1002,1004,1006],{"class":53,"line":608},[51,991,992],{"class":104},"    |",[51,994,995],{"class":108}," (pl.col(",[51,997,721],{"class":61},[51,999,977],{"class":108},[51,1001,547],{"class":104},[51,1003,982],{"class":108},[51,1005,951],{"class":61},[51,1007,987],{"class":108},[51,1009,1010,1013,1015,1017,1019,1021,1023],{"class":53,"line":613},[51,1011,1012],{"class":108},").select(",[51,1014,711],{"class":61},[51,1016,184],{"class":108},[51,1018,716],{"class":61},[51,1020,184],{"class":108},[51,1022,721],{"class":61},[51,1024,140],{"class":108},[51,1026,1028,1030,1033,1035,1037,1039,1041,1043,1045,1047],{"class":53,"line":1027},13,[51,1029,147],{"class":146},[51,1031,1032],{"class":108},"(clean.select(",[51,1034,711],{"class":61},[51,1036,184],{"class":108},[51,1038,880],{"class":61},[51,1040,184],{"class":108},[51,1042,951],{"class":61},[51,1044,782],{"class":108},[51,1046,161],{"class":146},[51,1048,164],{"class":108},[51,1050,1052,1054,1056,1059],{"class":53,"line":1051},14,[51,1053,147],{"class":146},[51,1055,172],{"class":108},[51,1057,1058],{"class":61},"\"could not convert:\"",[51,1060,1061],{"class":108},", failed.to_dicts())\n",[10,1063,1064,1067,1068,1070,1071,1075,1076,1078,1079,1082,1083,1085,1086,1088,1089,1092,1093,1095,1096,1098,1099,35],{},[14,1065,1066],{},"cast(strict=False)"," turns ",[14,1069,24],{}," into null ",[1072,1073,1074],"em",{},"knowingly"," — and because the original text is still in the ",[14,1077,208],{}," column, the failure can be listed. Dates are parsed with each known format in turn and ",[14,1080,1081],{},"pl.coalesce"," takes the first that works, so both the real Excel dates (which arrived as ",[14,1084,812],{},") and the typed ",[14,1087,227],{}," end up as proper dates. The ",[14,1090,1091],{},"failed"," frame is the honest output: one row whose amount was ",[14,1094,24],{},", for a person to decide about. Codes stay text, which is what they are — a code is never a number, even when it looks like one. Placeholder text such as ",[14,1097,24],{}," is discussed in ",[31,1100,1102],{"href":1101},"\u002Fadvanced-data-transformation-and-cleaning\u002Fhandling-missing-data-in-excel-reports\u002Freplace-placeholder-text-with-nan-in-pandas\u002F","Replace Placeholder Text with NaN in pandas",[234,1104,243,1110,243,1113,243,1116,243,1121,243,1128,243,1139,243,1145,243,1150,243,1153,243,1158,243,1161,243,1165,243,1172,243,1178,243,1181,243,1185,243,1188,243,1191,243,1198,243,1203,243,1206,243,1210,243,1213,243,1218,243,1225,243,1230],{"viewBox":1105,"role":237,"ariaLabelledBy":1106,"xmlns":241,"style":1109},"4 0 752 142",[1107,1108],"plt-fix-t","plt-fix-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[245,1111,1112],{"id":1107},"A read that never loses a value silently",[249,1114,1115],{"id":1108},"Read awkward columns as text with schema overrides, cast them explicitly with strict set to false, try each known date format and keep the first that parses, then list every value that failed to convert for review.",[253,1117],{"x":1118,"y":181,"width":1119,"height":1120,"fill":258},"4","752","142",[253,1122],{"x":1123,"y":1124,"width":1125,"height":1126,"rx":1127,"fill":265,"stroke":266,"style":411},"20.0","16.0","153.0","110.5","12",[1129,1130,1132],"g",{"transform":1131},"translate(84.5,29.0) scale(1.000)",[1133,1134],"path",{"d":1135,"fill":1136,"stroke":1137,"style":1138},"M6 3h9l4 4v14H6z M15 3v4h4","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[273,1140,1144],{"x":1141,"y":1142,"style":1143},"96.5","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Read as text",[273,1146,1149],{"x":1141,"y":1147,"style":1148},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","schema_overrides →",[273,1151,627],{"x":1141,"y":1152,"style":1148},"112.5",[53,1154],{"x1":1155,"y1":1156,"x2":1157,"y2":1156,"stroke":410,"style":411},"178.0","71.2","200.0",[413,1159],{"points":1160,"fill":416},"204.0,71.2 195.0,76.2 195.0,66.2",[253,1162],{"x":1163,"y":1124,"width":1125,"height":1126,"rx":1127,"fill":1164,"stroke":410,"style":411},"209.0","#f0f4ff",[1129,1166,1168],{"transform":1167},"translate(273.5,37.8) scale(1.000)",[1133,1169],{"d":1170,"fill":1136,"stroke":1171,"style":1138},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","var(--brand-strong,#4338ca)",[273,1173,1177],{"x":1174,"y":1175,"style":1176},"285.5","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Cast explicitly",[273,1179,826],{"x":1174,"y":1180,"style":1148},"103.8",[53,1182],{"x1":1183,"y1":1156,"x2":1184,"y2":1156,"stroke":410,"style":411},"367.0","389.0",[413,1186],{"points":1187,"fill":416},"393.0,71.2 384.0,76.2 384.0,66.2",[253,1189],{"x":1190,"y":1124,"width":1125,"height":1126,"rx":1127,"fill":390,"stroke":391,"style":411},"398.0",[1129,1192,1194],{"transform":1193},"translate(462.5,37.8) scale(1.000)",[1133,1195],{"d":1196,"fill":1136,"stroke":1197,"style":1138},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--teal-ink,#0b6157)",[273,1199,1202],{"x":1200,"y":1175,"style":1201},"474.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Dates",[273,1204,1205],{"x":1200,"y":1180,"style":1148},"coalesce of formats",[53,1207],{"x1":1208,"y1":1156,"x2":1209,"y2":1156,"stroke":410,"style":411},"556.0","578.0",[413,1211],{"points":1212,"fill":416},"582.0,71.2 573.0,76.2 573.0,66.2",[253,1214],{"x":1215,"y":1124,"width":1125,"height":1126,"rx":1127,"fill":1216,"stroke":1217,"style":411},"587.0","#fdefd8","var(--gold,#b4740a)",[1129,1219,1221],{"transform":1220},"translate(651.5,37.8) scale(1.000)",[1133,1222],{"d":1223,"fill":1136,"stroke":1224,"style":1138},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold-ink,#7a4e06)",[273,1226,1229],{"x":1227,"y":1175,"style":1228},"663.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Report failures",[273,1231,1232],{"x":1227,"y":1180,"style":1148},"original text kept",[37,1234,1236],{"id":1235},"step-5-blank-and-duplicate-headers-and-empty-sheets","Step 5 — Blank and duplicate headers, and empty sheets",[10,1238,1239],{},"Headers cause their own surprises. Look at the column names Polars produced, and at what an empty sheet does:",[42,1241,1243],{"className":95,"code":1242,"language":97,"meta":47,"style":47},"print(df.columns)\nrenamed = df.rename({\"__UNNAMED__4\": \"Flag\", \"Qty_1\": \"Qty returned\"})\nprint(renamed.columns)\n\ntry:\n    pl.read_excel(\"empty.xlsx\")\nexcept Exception as e:\n    print(type(e).__name__, \"-\", str(e).splitlines()[0])\nprint(pl.read_excel(\"empty.xlsx\", raise_if_empty=False).shape)\n",[14,1244,1245,1252,1284,1291,1295,1303,1313,1327,1360],{"__ignoreMap":47},[51,1246,1247,1249],{"class":53,"line":54},[51,1248,147],{"class":146},[51,1250,1251],{"class":108},"(df.columns)\n",[51,1253,1254,1257,1259,1262,1265,1268,1271,1273,1276,1278,1281],{"class":53,"line":118},[51,1255,1256],{"class":108},"renamed ",[51,1258,131],{"class":104},[51,1260,1261],{"class":108}," df.rename({",[51,1263,1264],{"class":61},"\"__UNNAMED__4\"",[51,1266,1267],{"class":108},": ",[51,1269,1270],{"class":61},"\"Flag\"",[51,1272,184],{"class":108},[51,1274,1275],{"class":61},"\"Qty_1\"",[51,1277,1267],{"class":108},[51,1279,1280],{"class":61},"\"Qty returned\"",[51,1282,1283],{"class":108},"})\n",[51,1285,1286,1288],{"class":53,"line":125},[51,1287,147],{"class":146},[51,1289,1290],{"class":108},"(renamed.columns)\n",[51,1292,1293],{"class":53,"line":143},[51,1294,122],{"emptyLinePlaceholder":121},[51,1296,1297,1300],{"class":53,"line":153},[51,1298,1299],{"class":104},"try",[51,1301,1302],{"class":108},":\n",[51,1304,1305,1308,1311],{"class":53,"line":167},[51,1306,1307],{"class":108},"    pl.read_excel(",[51,1309,1310],{"class":61},"\"empty.xlsx\"",[51,1312,140],{"class":108},[51,1314,1315,1318,1321,1324],{"class":53,"line":536},[51,1316,1317],{"class":104},"except",[51,1319,1320],{"class":146}," Exception",[51,1322,1323],{"class":104}," as",[51,1325,1326],{"class":108}," e:\n",[51,1328,1329,1332,1334,1337,1340,1343,1345,1348,1350,1352,1355,1357],{"class":53,"line":553},[51,1330,1331],{"class":146},"    print",[51,1333,172],{"class":108},[51,1335,1336],{"class":146},"type",[51,1338,1339],{"class":108},"(e).",[51,1341,1342],{"class":146},"__name__",[51,1344,184],{"class":108},[51,1346,1347],{"class":61},"\"-\"",[51,1349,184],{"class":108},[51,1351,479],{"class":146},[51,1353,1354],{"class":108},"(e).splitlines()[",[51,1356,181],{"class":146},[51,1358,1359],{"class":108},"])\n",[51,1361,1362,1364,1367,1369,1371,1374,1376,1378],{"class":53,"line":567},[51,1363,147],{"class":146},[51,1365,1366],{"class":108},"(pl.read_excel(",[51,1368,1310],{"class":61},[51,1370,184],{"class":108},[51,1372,1373],{"class":187},"raise_if_empty",[51,1375,131],{"class":104},[51,1377,874],{"class":146},[51,1379,1380],{"class":108},").shape)\n",[10,1382,1383,1384,1387,1388,1390,1391,1394,1395,1398,1399,1402,1403,1406,1407,35],{},"A blank header becomes ",[14,1385,1386],{},"__UNNAMED__4"," (the number is the column position) and a repeated ",[14,1389,80],{}," becomes ",[14,1392,1393],{},"Qty_1",". Neither is an error, but code that selects ",[14,1396,1397],{},"\"Qty\""," silently gets the first of the two, so rename deliberately right after reading — and if the positions can change between exports, find columns by header text rather than position. An empty sheet raises ",[14,1400,1401],{},"NoDataError","; ",[14,1404,1405],{},"raise_if_empty=False"," returns an empty frame instead, which suits batch jobs where an empty export is normal and should simply contribute no rows. Duplicate headers in pandas are covered in ",[31,1408,1410],{"href":1409},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-duplicate-column-names-when-reading-excel\u002F","Fix Duplicate Column Names When Reading Excel",[234,1412,243,1417,243,1420,243,1423,243,1426,243,1429,243,1433,243,1439,243,1442,243,1446,243,1450,243,1455,243,1457,243,1460,243,1462,243,1465,243,1468,243,1472,243,1474,243,1477,243,1479,243,1482,243,1485,243,1489,243,1491,243,1494,243,1496,243,1498,243,1501,243,1505,243,1507,243,1511,243,1513],{"viewBox":1413,"role":237,"ariaLabelledBy":1414,"xmlns":241,"style":1109},"4 0 752 208",[1415,1416],"plt-headers-t","plt-headers-d",[245,1418,1419],{"id":1415},"Header and sheet surprises and how Polars reports them",[249,1421,1422],{"id":1416},"A blank header becomes a column named __UNNAMED__ plus its position. A repeated header gets a suffix such as _1. An empty sheet raises NoDataError unless raise_if_empty is false. A cell that does not fit the inferred type becomes null without any message.",[253,1424],{"x":1118,"y":181,"width":1119,"height":1425,"fill":258},"208",[253,1427],{"x":1123,"y":1124,"width":1428,"height":262,"rx":181,"fill":258,"stroke":266,"style":267},"136.0",[253,1430],{"x":1431,"y":1124,"width":1432,"height":262,"rx":181,"fill":1164,"stroke":410,"style":424},"156.0","292.0",[273,1434,1438],{"x":1435,"y":1436,"style":1437},"302.0","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","what you get",[253,1440],{"x":1441,"y":1124,"width":1432,"height":262,"rx":181,"fill":1164,"stroke":410,"style":424},"448.0",[273,1443,1445],{"x":1444,"y":1436,"style":1437},"594.0","what to do",[253,1447],{"x":1123,"y":1448,"width":1428,"height":1449,"rx":181,"fill":265,"stroke":266,"style":267},"56.0","34.0",[273,1451,1454],{"x":263,"y":1452,"style":1453},"78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","blank header",[253,1456],{"x":1431,"y":1448,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1458,1386],{"x":1435,"y":1459,"style":1148},"77.0",[253,1461],{"x":1441,"y":1448,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1463,1464],{"x":1444,"y":1459,"style":1148},"rename right after reading",[253,1466],{"x":1123,"y":1467,"width":1428,"height":1449,"rx":181,"fill":265,"stroke":266,"style":267},"90.0",[273,1469,1471],{"x":263,"y":1470,"style":1453},"112.0","duplicate header",[253,1473],{"x":1431,"y":1467,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1475,1476],{"x":1435,"y":334,"style":1148},"Qty, Qty_1",[253,1478],{"x":1441,"y":1467,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1480,1481],{"x":1444,"y":334,"style":1148},"rename deliberately",[253,1483],{"x":1123,"y":1484,"width":1428,"height":1449,"rx":181,"fill":265,"stroke":266,"style":267},"124.0",[273,1486,1488],{"x":263,"y":1487,"style":1453},"146.0","empty sheet",[253,1490],{"x":1431,"y":1484,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1492,1401],{"x":1435,"y":1493,"style":1148},"145.0",[253,1495],{"x":1441,"y":1484,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1497,1405],{"x":1444,"y":1493,"style":1148},[253,1499],{"x":1123,"y":1500,"width":1428,"height":1449,"rx":181,"fill":265,"stroke":266,"style":267},"158.0",[273,1502,1504],{"x":263,"y":1503,"style":1453},"180.0","misfit cell",[253,1506],{"x":1431,"y":1500,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1508,1510],{"x":1435,"y":1509,"style":1148},"179.0","silent null",[253,1512],{"x":1441,"y":1500,"width":1432,"height":1449,"rx":181,"fill":258,"stroke":266,"style":267},[273,1514,1515],{"x":1444,"y":1509,"style":1148},"read as String, cast, report",[37,1517,1519],{"id":1518},"making-it-routine","Making it routine",[10,1521,1522,1523,1525,1526,35],{},"For a recurring import, write the expected schema down once — column names, the type each should end up as, and which columns are read as text first — and keep it next to the code as a dictionary. The reader then pins every column with ",[14,1524,645],{},", casts with a failure report, and fails the job if a required column is missing or the failure list is longer than an agreed threshold. That turns a silent data-quality problem into a visible, reviewable one, and when an export changes shape the job says so on the first run instead of producing quietly wrong totals for months. The same contract can be checked in pandas with a schema library, as in ",[31,1527,1529],{"href":1528},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-excel-data-with-pandera-schemas\u002F","Validate Excel Data with pandera Schemas",[37,1531,1533],{"id":1532},"common-pitfalls","Common pitfalls",[1535,1536,1537,1545,1555,1561,1567],"ul",{},[1538,1539,1540,1544],"li",{},[1541,1542,1543],"strong",{},"Trusting a clean-looking read."," Mismatched cells become nulls without a warning; compare with a text read.",[1538,1546,1547,1554],{},[1541,1548,1549,1550,1553],{},"Assuming ",[14,1551,1552],{},"infer_schema_length=None"," fixes everything."," It changes some types but still nulls out odd values.",[1538,1556,1557,1560],{},[1541,1558,1559],{},"Casting codes to numbers."," Codes are text; keep them as strings.",[1538,1562,1563,1566],{},[1541,1564,1565],{},"Selecting a duplicated header by name."," You get the first one; rename after reading.",[1538,1568,1569,1572],{},[1541,1570,1571],{},"One date format."," Try each known format and coalesce.",[37,1574,1576],{"id":1575},"conclusion","Conclusion",[10,1578,1579,1580,1583,1584,1586,1587,803,1589,1591,1592,1594,1595,1597],{},"Polars' ",[14,1581,1582],{},"read_excel"," infers each column's type from the first rows and turns cells that do not fit into nulls without telling you. Detect it by comparing a typed read with an all-text read (",[14,1585,623],{},"); prevent it by pinning awkward columns to ",[14,1588,627],{},[14,1590,645],{},", then casting explicitly with ",[14,1593,826],{}," and listing every value that failed. Rename blank and duplicate headers straight after reading, and use ",[14,1596,1405],{}," where empty sheets are expected.",[37,1599,1601],{"id":1600},"frequently-asked-questions","Frequently asked questions",[10,1603,1604,1607],{},[1541,1605,1606],{},"Why are some values null after reading Excel with Polars?","\nPolars infers each column's type from the first rows, and cells that do not fit that type, such as text in a numeric column, are converted to null without an error.",[10,1609,1610,1613],{},[1541,1611,1612],{},"How do I read every Excel column as text in Polars?","\nPass infer_schema_length=0 to read_excel, which reads all columns as String, or set specific columns to pl.String with schema_overrides.",[10,1615,1616,1619],{},[1541,1617,1618],{},"How do I find which values Polars could not convert?","\nRead the sheet once as text and once with types, then list cells that are not null in the text read but null in the typed read.",[10,1621,1622,1625],{},[1541,1623,1624],{},"How do I stop Polars failing on an empty Excel sheet?","\nPass raise_if_empty=False to read_excel to get an empty DataFrame instead of a NoDataError.",[37,1627,1629],{"id":1628},"related","Related",[1535,1631,1632,1638,1645,1652],{},[1538,1633,1634,1635,1637],{},"Up one level: ",[31,1636,34],{"href":33}," — fast Excel reading with Polars.",[1538,1639,1640,1644],{},[31,1641,1643],{"href":1642},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fread-an-excel-file-with-polars-read-excel\u002F","Read an Excel File with Polars read_excel"," — the basics.",[1538,1646,1647,1651],{},[31,1648,1650],{"href":1649},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcheck-excel-data-types-with-pandas\u002F","Check Excel Data Types with pandas"," — the same question in pandas.",[1538,1653,1654,1658],{},[31,1655,1657],{"href":1656},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fscan-and-filter-many-excel-files-lazily-with-polars\u002F","Scan and Filter Many Excel Files Lazily with Polars"," — schema agreement across many files.",[1660,1661,1662],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":47,"searchDepth":118,"depth":118,"links":1664},[1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675],{"id":39,"depth":118,"text":40},{"id":88,"depth":118,"text":89},{"id":433,"depth":118,"text":434},{"id":631,"depth":118,"text":632},{"id":819,"depth":118,"text":820},{"id":1235,"depth":118,"text":1236},{"id":1518,"depth":118,"text":1519},{"id":1532,"depth":118,"text":1533},{"id":1575,"depth":118,"text":1576},{"id":1600,"depth":118,"text":1601},{"id":1628,"depth":118,"text":1629},"2026-10-02","Polars reads Excel fast, but its type inference can turn mismatched cells into nulls without a word. This page shows how a code like A-77 or a text date silently disappears, how infer_schema_length and schema_overrides change that, how to read raw text and cast with a report of every failure, and how to handle blank and duplicate headers, empty sheets and mixed date formats.","md",[1680,1682,1684,1686],{"q":1606,"a":1681},"Polars infers each column's type from the first rows, and cells that do not fit that type, such as text in a numeric column, are converted to null without an error.",{"q":1612,"a":1683},"Pass infer_schema_length=0 to read_excel, which reads all columns as String, or set specific columns to pl.String with schema_overrides.",{"q":1618,"a":1685},"Read the sheet once as text and once with types, then list cells that are not null in the text read but null in the typed read.",{"q":1624,"a":1687},"Pass raise_if_empty=False to read_excel to get an empty DataFrame instead of a NoDataError.","fix schema and type errors when reading excel with polars",null,{"breadcrumb":1691},[1692,1695,1698],{"name":1693,"item":1694},"Home","\u002F",{"name":1696,"item":1697},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":34,"item":33},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars",{"title":1701,"description":1702},"Fix Schema and Type Problems Reading Excel with Polars","Polars read_excel can null out values that do not match the inferred type. Detect silent nulls, use infer_schema_length and schema_overrides, read as String and cast with a failure report, and handle odd headers.","fix-schema-and-type-errors-when-reading-excel-with-polars","advanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Ffix-schema-and-type-errors-when-reading-excel-with-polars\u002Findex",[1706,1707],"polars","reading-excel","how-to","b8ZuXCqJUPiGGz8c9JrhmaM_CZOLMpXiYJenirWSUUM",[1711,1715],{"title":1712,"path":1713,"stem":1714,"children":-1},"Convert pandas Excel Code to Polars","\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fconvert-pandas-excel-code-to-polars","advanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fconvert-pandas-excel-code-to-polars\u002Findex",{"title":1716,"path":1717,"stem":1718,"children":-1},"Join and Pivot Excel Data with Polars","\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fjoin-and-pivot-excel-data-with-polars","advanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fjoin-and-pivot-excel-data-with-polars\u002Findex",[1720,1722],{"path":1721,"title":1696},"\u002Fadvanced-data-transformation-and-cleaning",{"path":1723,"title":34},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow",[],[1726,1729,1732,1733,1734,1737],{"path":1727,"title":1728,"kind":1708},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fclean-and-aggregate-excel-data-with-polars","Clean and Aggregate Excel Data with Polars Expressions",{"path":1730,"title":1731,"kind":1708},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fclean-wide-excel-sheets-with-polars-column-selectors","Clean Wide Excel Sheets with Polars Column Selectors",{"path":1713,"title":1712,"kind":1708},{"path":1717,"title":1716,"kind":1708},{"path":1735,"title":1736,"kind":1708},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fread-an-excel-file-with-polars-read-excel","Read an Excel File with polars.read_excel",{"path":1738,"title":1739,"kind":1708},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fread-multiple-excel-sheets-with-polars","Read Multiple Excel Sheets with Polars",1790972098216]