{"record":{"id":"d10b4b1ba600dfde","repo":"getgrav/grav","slug":"badly-formatted-csv-line-line","errorCode":null,"errorMessage":"Badly formatted CSV line: {line}","messagePattern":"Badly formatted CSV line: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/Formatter/CsvFormatter.php","lineNumber":124,"sourceCode":"        // Get the data\n        $list = [];\n        $line = null;\n        try {\n            foreach ($lines as $line) {\n                if (!empty($line)) {\n                    $csv_line = str_getcsv($line, $delimiter);\n\n                    if ($null_replace) {\n                        array_walk($csv_line, static function (&$el) use ($null_replace) {\n                            $el = str_replace($null_replace, \"\\0\", $el);\n                        });\n                    }\n\n                    $list[] = array_combine($header, $csv_line);\n                }\n            }\n        } catch (Exception) {\n            throw new RuntimeException('Badly formatted CSV line: ' . $line);\n        }\n\n        return $list;\n    }\n\n    /**\n     * @param array $line\n     * @param string $delimiter\n     * @return string\n     */\n    protected function encodeLine(array $line, string $delimiter): string\n    {\n        foreach ($line as $key => &$value) {\n            // Oops, we need to convert the line to a string.\n            if (!is_scalar($value)) {\n                if (is_array($value) || $value instanceof JsonSerializable || $value instanceof stdClass) {\n                    $value = json_encode($value);\n                } elseif (is_object($value)) {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/Formatter/CsvFormatter.php#L106-L142","documentation":"CsvFormatter::decode() parses each line with str_getcsv() and merges it with the header via array_combine($header, $csv_line) inside a try/catch; any Exception thrown while processing a line is rethrown as 'Badly formatted CSV line: <line>'. The dominant cause is a field-count mismatch between a row and the header — one side of array_combine longer than the other — typically from unquoted delimiters, missing trailing delimiters, or the wrong delimiter being used.","triggerScenarios":"A data row with more fields than the header (unquoted delimiter inside a value) or fewer (missing trailing comma); a delimiter mismatch — the file is semicolon/tab separated while the formatter uses commas, so counts never line up; rows of a different width appended from another source.","commonSituations":"Spreadsheet exports with unquoted commas in text fields; concatenating CSVs that share a schema prefix but drift later; European locale exports (semicolon delimiter) read with the default comma config; hand-edited rows.","solutions":["Inspect the line named in the message and balance its field count against the header.","Match the delimiter: pass it explicitly decode($data, ';') or configure the CsvFormatter — a systematic wrong delimiter produces this error on every row.","Re-export with proper quoting so values containing the delimiter are enclosed in quotes.","Pre-validate rows before decoding: count(str_getcsv($line, $del)) must equal count($header); skip or report offenders."],"exampleFix":"// before\n$list = $formatter->decode($raw); // Badly formatted CSV line: 1;2;3;4\n\n// after: pass the actual delimiter\n$list = $formatter->decode($raw, ';');\n\n// or guard rows against the header width\n$header = str_getcsv($headerLine, $del);\n$clean = array_filter($lines, fn($l) => count(str_getcsv($l, $del)) === count($header));","handlingStrategy":"validation","validationCode":"// Verify every row's width matches the header before decode()\n$lines = preg_split('/\\r\\n|\\r|\\n/', trim($data));\n$header = str_getcsv((string) array_shift($lines), $del);\nforeach ($lines as $l) {\n    if ($l !== '' && count(str_getcsv($l, $del)) !== count($header)) {\n        // report/skip this row now instead of failing the whole decode\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    $list = $formatter->decode($data);\n} catch (\\RuntimeException $e) {\n    if (preg_match('/Badly formatted CSV line/', $e->getMessage())) {\n        // row-level data error: log and continue with remaining rows if acceptable\n    }\n}","preventionTips":["Pin the delimiter explicitly for locale-sensitive exports (comma vs semicolon).","Require quoting of values containing the delimiter when generating CSV.","Validate row widths on ingest and reject offending rows with context."],"tags":["php","grav","csv","data-integrity","parse-error","delimiter"],"backgroundTag":"csv-column-count-mismatch","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}