{"record":{"id":"5952f29b0710a5ef","repo":"gchq/CyberChef","slug":"input-must-in-the-format-lat1-lng1-lat2-lng2","errorCode":null,"errorMessage":"Input must in the format lat1, lng1, lat2, lng2","messagePattern":"Input must in the format lat1, lng1, lat2, lng2","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/HaversineDistance.mjs","lineNumber":39,"sourceCode":"        this.name = \"Haversine distance\";\n        this.module = \"Default\";\n        this.description = \"Returns the distance between two pairs of GPS latitude and longitude co-ordinates in metres.<br><br>e.g. <code>51.487263,-0.124323, 38.9517,-77.1467</code>\";\n        this.infoURL = \"https://wikipedia.org/wiki/Haversine_formula\";\n        this.inputType = \"string\";\n        this.outputType = \"number\";\n        this.args = [];\n    }\n\n    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {number}\n     */\n    run(input, args) {\n\n        const values = input.match(/^(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?)$/);\n        if (!values) {\n            throw new OperationError(\"Input must in the format lat1, lng1, lat2, lng2\");\n        }\n\n        const lat1 = parseFloat(values[1]);\n        const lng1 = parseFloat(values[3]);\n        const lat2 = parseFloat(values[5]);\n        const lng2 = parseFloat(values[7]);\n\n        const TO_RAD = Math.PI / 180;\n        const dLat = (lat2-lat1) * TO_RAD;\n        const dLng = (lng2-lng1) * TO_RAD;\n        const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * TO_RAD) * Math.cos(lat2 * TO_RAD) * Math.sin(dLng/2) * Math.sin(dLng/2);\n        const metres = 6371000 * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\n\n        return metres;\n\n    }\n\n}","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/HaversineDistance.mjs#L21-L57","documentation":"Thrown by Haversine Distance when the input fails to match the strict regex for four decimal coordinates. The expected format is `lat1, lng1, lat2, lng2` where each value is an optional minus, integer digits, and optional decimal fraction. Whitespace is only tolerated after the commas (one optional space).","triggerScenarios":"Missing a coordinate; extra text; using semicolons or tabs instead of commas; values in scientific/engineering notation (1e3); DMS coordinates (51°30'); trailing units (m/deg); inconsistent spacing ('lat1,lng1,lat2,lng2' with no spaces works, but 'lat1 ,lng1' fails).","commonSituations":"Pasting coordinates from a map UI that includes cardinal letters (N/S/E/W) or degree symbols; mixing decimal and DMS; CSV export using a different separator; negative longitude missing the minus.","solutions":["Format the input as four plain decimal numbers separated by commas: 'lat1, lng1, lat2, lng2'.","Strip cardinal letters, degree symbols, minutes/seconds - convert DMS to decimal first.","Ensure exactly one optional space after each comma and no spaces inside numbers.","Validate the line with the same regex before submitting."],"exampleFix":"// before\nrun(\"51.487263N, -0.124323W, 38.9517, -77.1467\", []);\n// after - decimals only, no cardinal letters\nrun(\"51.487263, -0.124323, 38.9517, -77.1467\", []);","handlingStrategy":"validation","validationCode":"const HAVERSINE_RE = /^(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?), ?(-?\\d+(\\.\\d+)?)$/;\nfunction assertHaversineInput(input) {\n  if (!HAVERSINE_RE.test(input.trim())) {\n    throw new Error('Input must be four decimal coords: lat1, lng1, lat2, lng2');\n  }\n}","typeGuard":"function isHaversineInput(input) {\n  return HAVERSINE_RE.test(typeof input === 'string' ? input.trim() : '');\n}","tryCatchPattern":"try {\n  metres = haversine.run(input, []);\n} catch (e) {\n  if (e instanceof OperationError && /format lat1/i.test(e.message)) {\n    // normalise: strip cardinal letters and degree symbols, then retry\n    const clean = input.replace(/[NSEW]/gi, '').replace(/°/g, '');\n    metres = haversine.run(clean, []);\n  } else throw e;\n}","preventionTips":["Convert DMS to decimal before invoking.","Strip cardinal letters (N/S/E/W) and degree symbols.","Keep exactly one optional space after each comma.","Pre-validate with the same regex."],"tags":["haversine","geo","coordinate-format","regex","argument-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}