{"record":{"id":"76d243da5142252e","repo":"gitlabhq/gitlabhq","slug":"end-name-must-be-greater-than-start-name","errorCode":null,"errorMessage":"#{end_name} must be greater than #{start_name}","messagePattern":"#(.+?) must be greater than #(.+?)","errorType":"exception","errorClass":"Gitlab::Graphql::Errors::ArgumentError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/notes/create/latest_diff_note.rb","lineNumber":82,"sourceCode":"\n        private\n\n        def validate_line_range!(args)\n          validate_end_line_has_start!(args[:end_new_line], args[:new_line], 'newLine', 'endNewLine')\n          validate_end_line_has_start!(args[:end_old_line], args[:old_line], 'oldLine', 'endOldLine')\n        end\n\n        def validate_end_line_has_start!(end_line, start_line, start_name, end_name)\n          return unless end_line\n\n          unless start_line\n            raise Gitlab::Graphql::Errors::ArgumentError,\n              \"#{start_name} is required when #{end_name} is provided\"\n          end\n\n          return if end_line > start_line\n\n          raise Gitlab::Graphql::Errors::ArgumentError,\n            \"#{end_name} must be greater than #{start_name}\"\n        end\n\n        def create_note_params(noteable, args)\n          super.merge({\n            type: 'DiffNote',\n            position: position(noteable, args),\n            merge_request_diff_head_sha: args[:head_sha]\n          })\n        end\n\n        def position(noteable, args)\n          resolve_result = ::MergeRequests::ResolveDiffPositionService.new(\n            noteable.project,\n            current_user,\n            merge_request: noteable,\n            file_path: args[:file_path],\n            new_line: args[:new_line],","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/gitlabhq/gitlabhq/blob/55ee20384a1f55cb0e362dee1d07149613b1b9bf/app/graphql/mutations/notes/create/latest_diff_note.rb#L64-L100","documentation":"The same validate_end_line_has_start! in LatestDiffNote also checks ordering: after confirming the start line exists, it requires end_line > start_line, otherwise it raises ArgumentError '<end> must be greater than <start>'. A range comment must span forward in the diff; equal or inverted ranges are rejected before the note is created.","triggerScenarios":"Calling the mutation with newLine: 50, endNewLine: 50 (equal), or newLine: 50, endNewLine: 42 (inverted). The comparison runs right after the pairing check in ready?.","commonSituations":"Drag-select in a custom diff viewer that reports rows in mouse-up order regardless of direction; off-by-one when normalizing 0-based UI rows to 1-based diff lines; passing coordinates as (x, y) where the API expects (start, end).","solutions":["Normalize before sending: start = Math.min(a, b); end = Math.max(a, b)","Treat a single-row selection (start === end) as a plain line comment: send only newLine/oldLine without end* fields","Check end > start after converting UI row indexes to diff line numbers"],"exampleFix":"// before\nawait gql(CREATE_NOTE, { ..., newLine: 50, endNewLine: 42 });\n\n// after\nconst [start, end] = selection[0] <= selection[1]\n  ? selection : [selection[1], selection[0]];\nawait gql(CREATE_NOTE, { ..., newLine: start, endNewLine: end });","handlingStrategy":"validation","validationCode":"function normalizeRange(a, b) {\n  if (a == null && b == null) return null;\n  if (a == null || b == null) return { start: a ?? b, end: null }; // single line\n  return { start: Math.min(a, b), end: Math.max(a, b) > Math.min(a, b) ? Math.max(a, b) : null }; // equal -> single line\n}","typeGuard":null,"tryCatchPattern":"On /must be greater than/, swap or normalize start/end (min/max) client-side and retry; if start === end, resend without the end* argument.","preventionTips":["Normalize selection coordinates with min/max before sending","Convert 0-based UI row indexes to 1-based diff line numbers carefully"],"tags":["gitlab","graphql","notes","diff","range-validation"],"backgroundTag":"graphql-argument-validation","analyzedSha":"55ee20384a1f55cb0e362dee1d07149613b1b9bf","analyzedAt":"2026-08-21T14:22:27.782Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}