{"record":{"id":"e9c092846d96371f","repo":"iOfficeAI/OfficeCLI","slug":"sparkline-requires-datarange-or-range-data","errorCode":null,"errorMessage":"Sparkline requires 'dataRange' (or 'range'/'data') property (e.g. A1:E1)","messagePattern":"Sparkline requires 'dataRange' \\(or 'range'/'data'\\) property \\(e\\.g\\. A1:E1\\)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Drawings.cs","lineNumber":982,"sourceCode":"\n        // CONSISTENCY(canonical-key): 'location'/'dataRange' are canonical;\n        // 'cell'/'range'/'data' retained as legacy aliases.\n        // R12a: also accept the host cell from the parent path tail\n        // (e.g. `add /Sheet1/F1 sparkline --prop dataRange=A1:E1`), mirroring\n        // how cell/cf Add derive their target from the path. Explicit\n        // location=/cell= still wins.\n        var spkPathTail = spkSegments.Length > 1\n            && Regex.IsMatch(spkSegments[1], @\"^[A-Z]+\\d+$\", RegexOptions.IgnoreCase)\n            ? spkSegments[1].ToUpperInvariant() : null;\n        var spkCell = properties.GetValueOrDefault(\"location\")\n            ?? properties.GetValueOrDefault(\"cell\")\n            ?? spkPathTail\n            ?? throw new ArgumentException(\"Sparkline requires 'location' (or 'cell') property (e.g. F1)\");\n        var spkRange = properties.GetValueOrDefault(\"dataRange\")\n            ?? properties.GetValueOrDefault(\"datarange\")\n            ?? properties.GetValueOrDefault(\"range\")\n            ?? properties.GetValueOrDefault(\"data\")\n            ?? throw new ArgumentException(\"Sparkline requires 'dataRange' (or 'range'/'data') property (e.g. A1:E1)\");\n\n        // OOXML xm:sqref is ST_Sqref (bare cell address, no sheet prefix —\n        // sheet is implied by the parent worksheet). Excel silently drops the\n        // entire <extLst> on load if sqref carries a sheet prefix.\n        spkCell = NormalizeSparklineSqref(spkCell, spkSheetName);\n        // A location that is not a real cell reference (\"XYZ\", empty) wrote a\n        // semantically dead <xne:sqref> anchor with no warning; validate the\n        // final sqref like every other cell-ref input.\n        if (string.IsNullOrWhiteSpace(spkCell)\n            || !Regex.IsMatch(spkCell, @\"^\\$?[A-Za-z]{1,3}\\$?\\d+(:\\$?[A-Za-z]{1,3}\\$?\\d+)?$\"))\n            throw new ArgumentException(\n                $\"Invalid sparkline 'location': '{spkCell}'. Expected a cell reference like F1 (or a range like F1:F5).\");\n        ParseCellReference(spkCell.Replace(\"$\", \"\").Split(':')[0]);\n\n        // Determine sparkline type\n        // bt-2: reject invalid types (e.g. \"bar\") instead of silently mapping\n        // to Line. Sparkline OOXML has exactly three types: line/column/stacked\n        // (winloss is an alias for stacked).","sourceCodeStart":964,"sourceCodeEnd":1000,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Drawings.cs#L964-L1000","documentation":"Thrown by AddSparkline when no source data range can be resolved. The data range is looked up under canonical `dataRange`, then aliases `datarange`, `range`, `data`; if none are present the ?? chain throws. The data range is required because a sparkline with no series data is meaningless and would write a dead XML element.","triggerScenarios":"Calling `add /Sheet1/F1 sparkline --prop location=F1` with no data range key, or using an unsupported alias like `source=` or `values=`. The canonical key is `dataRange`.","commonSituations":"Assuming the sparkline infers its data from the host cell; misspelling `dataRange` as `data-range` or `dataset`; providing only the type/color props.","solutions":["Add `--prop dataRange=A1:E1` (the series the sparkline visualizes).","Alternatively use alias `range=` or `data=`."],"exampleFix":"// before\nadd ./book.xlsx /Sheet1/F1 sparkline --prop location=F1 --prop type=line\n// after\nadd ./book.xlsx /Sheet1/F1 sparkline --prop location=F1 --prop dataRange=A1:E1","handlingStrategy":"validation","validationCode":"var dataRange = props.GetValueOrDefault(\"dataRange\")\n    ?? props.GetValueOrDefault(\"datarange\")\n    ?? props.GetValueOrDefault(\"range\")\n    ?? props.GetValueOrDefault(\"data\");\nif (string.IsNullOrWhiteSpace(dataRange))\n    throw new InvalidOperationException(\"Sparkline requires a data range (dataRange=)\");","typeGuard":"static bool HasSparklineDataRange(IReadOnlyDictionary<string,string> p)\n    => new[]{\"dataRange\",\"datarange\",\"range\",\"data\"}\n        .Any(k => !string.IsNullOrWhiteSpace(p.GetValueOrDefault(k)));","tryCatchPattern":"try { handler.AddSparkline(...); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"requires 'dataRange'\"))\n{ /* prompt for the source data range */ }","preventionTips":["Always pass dataRange=; it is the series the sparkline draws.","Use the canonical key `dataRange`, not `range`/`data` (those are legacy aliases)."],"tags":["excel","sparkline","missing-property","data-range","input-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}