{"record":{"id":"229a3c85e89736cb","repo":"gchq/CyberChef","slug":"unable-to-parse-json-to-csv-err-tostring","errorCode":null,"errorMessage":"Unable to parse JSON to CSV: ${err.toString()}","messagePattern":"Unable to parse JSON to CSV: (.+?)","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/JSONToCSV.mjs","lineNumber":104,"sourceCode":"        // Record values so they don't have to be passed to other functions explicitly\n        this.cellDelim = cellDelim;\n        this.rowDelim = rowDelim;\n        this.flattened = input;\n        if (!(this.flattened instanceof Array)) {\n            this.flattened = [input];\n        }\n\n        try {\n            return this.toCSV();\n        } catch (err) {\n            try {\n                this.flattened = flatten(input);\n                if (!(this.flattened instanceof Array)) {\n                    this.flattened = [this.flattened];\n                }\n                return this.toCSV(true);\n            } catch (err) {\n                throw new OperationError(\"Unable to parse JSON to CSV: \" + err.toString());\n            }\n        }\n    }\n\n    /**\n     * Correctly escapes a cell's contents based on the cell and row delimiters.\n     *\n     * @param {string} data\n     * @param {boolean} force - Whether to force conversion of data to fit in a cell\n     * @returns {string}\n     */\n    escapeCellContents(data, force=false) {\n        if (data !== \"string\") {\n            const isPrimitive = data == null || typeof data !== \"object\";\n            if (isPrimitive) data = `${data}`;\n            else if (force) data = JSON.stringify(data);\n        }\n","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/JSONToCSV.mjs#L86-L122","documentation":"Thrown by JSON to CSV after BOTH conversion attempts fail: the primary toCSV() and a fallback that flattens the structure and retries. The error captures whichever exception the fallback path raised (flatten() or toCSV(true)), reported via err.toString().","triggerScenarios":"Input JSON that is neither a flat record nor an array of flat records, where flattening still yields something toCSV cannot serialise: a scalar primitive at the top level, a structure with circular references, or a record whose flattened cells still contain nested objects/arrays the formatter rejects.","commonSituations":"Trying to convert a single nested object or a deeply-nested/ragged array of objects. Passing already-CSV text by mistake. Objects containing mixed array/object leaf values that do not flatten cleanly.","solutions":["Pre-shape the input into an array of flat, uniformly-keyed objects.","Use JQ or JSONata upstream to project only scalar fields before conversion.","Remove or stringify nested values so flattening produces leaf scalars.","Confirm the input is actually JSON (not CSV/TSV) before this operation."],"exampleFix":"// before: nested object that cannot be tabulated\nchef.JSONToCSV({ user: { name: 'Ann', addr: { city: 'X' } } });\n// after: flatten to scalar fields first\nchef.JSONToCSV([{ name: 'Ann', city: 'X' }]);","handlingStrategy":"validation","validationCode":"function normaliseForCsv(parsed) {\n  const arr = Array.isArray(parsed) ? parsed : [parsed];\n  return arr.map(o =>\n    Object.fromEntries(Object.entries(o).map(([k, v]) =>\n      [k, (v !== null && typeof v === 'object') ? JSON.stringify(v) : v]))\n  );\n}","typeGuard":"function isTabulatable(parsed) {\n  const arr = Array.isArray(parsed) ? parsed : [parsed];\n  return arr.every(o => o && typeof o === 'object' &&\n    Object.values(o).every(v => v === null || typeof v !== 'object'));\n}","tryCatchPattern":"try {\n  return chef.JSONToCSV(input);\n} catch (e) {\n  if (/Unable to parse JSON to CSV/.test(e.message))\n    throw new Error('Flatten the JSON to an array of scalar-field records first');\n  throw e;\n}","preventionTips":["Project nested objects to flat scalar fields before converting.","Use JQ/JSONata upstream to select uniform keys.","Stringify any remaining nested leaves."],"tags":["json","csv","conversion","validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}