{"record":{"id":"88e131aabbb646cb","repo":"iOfficeAI/OfficeCLI","slug":"sheet-not-found-cfsheetname","errorCode":null,"errorMessage":"Sheet not found: {cfSheetName}","messagePattern":"Sheet not found: (.+?)","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cf.cs","lineNumber":126,"sourceCode":"                return Add(parentPath, \"cfextended\", position, properties);\n            // R10: Reject unknown CF types instead of silently falling through to\n            // dataBar. The `cf` alias (AddCf) already throws on unknowns; mirror\n            // the behavior here so both `--type cf` and `--type conditionalformatting`\n            // share the same allowlist (CONSISTENCY(cf-type-allowlist)). `databar`\n            // is the documented default for this alias, so allow it explicitly.\n            if (cfTypeLower is not \"databar\")\n            {\n                throw new ArgumentException(\n                    $\"Unknown CF type '{cfTypeProp}'. Valid: databar, iconset, colorscale, formula, cellIs, \"\n                    + \"top10, topPercent, bottom, bottomPercent, aboveAverage, belowAverage, \"\n                    + \"uniqueValues, duplicateValues, containsText, notContains, beginsWith, endsWith, \"\n                    + \"containsBlanks, notContainsBlanks, containsErrors, notContainsErrors, dateOccurring.\");\n            }\n        }\n        var cfSegments = parentPath.TrimStart('/').Split('/', 2);\n        var cfSheetName = cfSegments[0];\n        var cfWorksheet = FindWorksheet(cfSheetName)\n            ?? throw new ArgumentException($\"Sheet not found: {cfSheetName}\");\n\n        // R22-2: a path-tail range (/Sheet1/A1:A3) is the sqref fallback before\n        // the hardcoded \"A1:A10\" — previously csSegments[1] was silently ignored.\n        var cfPathRange = cfSegments.Length > 1 && !string.IsNullOrEmpty(cfSegments[1]) ? cfSegments[1] : \"A1:A10\";\n        var sqref = ValidateSqref(properties.GetValueOrDefault(\"sqref\") ?? properties.GetValueOrDefault(\"range\") ?? properties.GetValueOrDefault(\"ref\", cfPathRange), \"ref\");\n        var minVal = properties.ContainsKey(\"min\") ? properties[\"min\"] : (string?)null;\n        var maxVal = properties.ContainsKey(\"max\") ? properties[\"max\"] : (string?)null;\n        // The schema documents min/max as \"numeric or 'auto'\". 'auto' is the\n        // automatic-bound sentinel, NOT a literal value: emitting it as a\n        // numeric cfvo (<cfvo type=\"num\" val=\"auto\"/>) is malformed and Excel\n        // silently drops the whole data bar. Map it back to null so the cfvo\n        // builders below pick the type=\"min\"/type=\"max\" (and x14 AutoMin/AutoMax)\n        // branches — identical to the user omitting the bound entirely.\n        if (string.Equals(minVal, \"auto\", StringComparison.OrdinalIgnoreCase)) minVal = null;\n        if (string.Equals(maxVal, \"auto\", StringComparison.OrdinalIgnoreCase)) maxVal = null;\n        var cfColor = properties.GetValueOrDefault(\"color\", \"638EC6\");\n        var normalizedColor = ParseHelpers.NormalizeArgbColor(cfColor);\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cf.cs#L108-L144","documentation":"Thrown by AddDataBar when FindWorksheet(cfSheetName) returns null. The sheet name is the first segment of parentPath after trimming the leading slash. This fires after the type-allowlist check (498) passes, so the type was valid (or defaulted to databar) but the sheet segment does not resolve to a worksheet.","triggerScenarios":"Add type=cf or type=conditionalformatting with parentPath=\"/BadSheet\" or a path whose sheet segment is not a worksheet. A path-tail range (e.g. /Sheet1/A1:A3) is fine because only the first segment is used for the sheet lookup; the range is consumed later as the sqref fallback.","commonSituations":"Sheet renamed or deleted after the path was captured. Script reuses a sheet name from a different workbook. Typo or trailing whitespace in the sheet segment.","solutions":["Confirm the sheet exists via a Get on / and use the exact name.","Create the sheet first if it is missing.","Ensure the path begins with /<exactSheetName> (a trailing /A1:A10 range is optional but allowed)."],"exampleFix":"// before\nhandler.Add(\"/SheetZ\", \"cf\", null, props); // SheetZ missing\n\n// after\nhandler.Add(\"/Sheet1\", \"cf\", null, props);","handlingStrategy":"validation","validationCode":"string sheet = parentPath.TrimStart('/').Split('/', 2)[0];\nvar sheets = handler.Query(\"/\");\nif (!sheets.Any(s => string.Equals(s.Name, sheet, StringComparison.OrdinalIgnoreCase)))\n    throw new InvalidOperationException($\"Sheet not found: {sheet}\");\nhandler.Add(parentPath, \"cf\", null, props);","typeGuard":"static bool SheetExists(IExcelHandler h, string sheet)\n    => h.Query(\"/\").Any(s => string.Equals(s.Name, sheet, StringComparison.OrdinalIgnoreCase));","tryCatchPattern":"try { handler.Add(parentPath, \"cf\", null, props); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Sheet not found\"))\n{ /* create the sheet or report the missing name */ }","preventionTips":["Resolve the sheet segment from a current sheet listing before Add.","Create the sheet first if it does not exist.","Note the path-tail range (/Sheet1/A1:A10) is optional but the sheet segment is mandatory."],"tags":["excel","ooxml","conditional-formatting","cf","sheet-not-found","argument"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}