{"record":{"id":"2c564946ebc43089","repo":"iOfficeAI/OfficeCLI","slug":"progid-progid-contains-invalid-characters-onl","errorCode":null,"errorMessage":"progId '{progId}' contains invalid characters. Only letters, digits, '.', '_', '-' are allowed.","messagePattern":"progId '(.+?)' contains invalid characters\\. Only letters, digits, '\\.', '_', '-' are allowed\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/OleHelper.cs","lineNumber":505,"sourceCode":"    /// </summary>\n    public static void ValidateProgId(string progId)\n    {\n        if (progId == null) return;\n        if (progId.Length > 39)\n            throw new ArgumentException(\n                $\"progId '{progId}' exceeds 39 characters (limit: 39, actual: {progId.Length}).\");\n        if (progId.Length > 0 && char.IsDigit(progId[0]))\n            throw new ArgumentException(\n                $\"progId '{progId}' cannot start with a digit.\");\n        // COM ProgID character set: letters, digits, '.', '_', '-'. Anything\n        // else (notably XML-unsafe characters like '<', '>', '&', '\"') would\n        // either corrupt the OOXML progId attribute or be rejected by Office\n        // on reopen. Reject early with an actionable error instead of letting\n        // bad bytes land in the package.\n        foreach (var ch in progId)\n        {\n            if (!(char.IsLetterOrDigit(ch) || ch == '.' || ch == '_' || ch == '-'))\n                throw new ArgumentException(\n                    $\"progId '{progId}' contains invalid characters. Only letters, digits, '.', '_', '-' are allowed.\");\n        }\n    }\n\n    /// <summary>\n    /// Normalize and validate the caller-supplied <c>display</c> property\n    /// for an OLE object. Canonical values are <c>\"icon\"</c> (show the file\n    /// as a clickable icon preview) and <c>\"content\"</c> (show the embedded\n    /// file's first page as a live picture). Any other value — including\n    /// ambiguous synonyms like <c>\"embed\"</c>, <c>\"invisible\"</c>, numbers,\n    /// or boolean strings — is rejected with <see cref=\"ArgumentException\"/>\n    /// so the user is told their input was wrong instead of silently\n    /// falling back to \"icon\". Used by Word/PPT Add and Set.\n    /// </summary>\n    public static string NormalizeOleDisplay(string value)\n    {\n        if (value == null)\n            throw new ArgumentException(","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/OleHelper.cs#L487-L523","documentation":"Thrown by OleHelper.ValidateProgId when a progId string contains any character outside the COM-allowed set: letters, digits, '.', '_', '-'. Characters like '<', '>', '&', '\"', spaces, or other punctuation are rejected because they would either corrupt the OOXML progId attribute (XML-unsafe characters) or be rejected by Office on reopen. The check iterates every character after the length and digit-start checks pass.","triggerScenarios":"Calling Add ole or Set ole with a progId containing spaces (e.g. 'My Prog Id'), XML-unsafe characters ('Doc<Name>'), ampersands ('A&B'), quotes ('My\"Id'), or any other punctuation not in {letter, digit, '.', '_', '-'}. The foreach loop over each character rejects the first invalid one it finds.","commonSituations":"A progId auto-generated from a filename with spaces or special characters. A copy-paste from a rich text source that introduced invisible or special characters. A user who included a description instead of a clean identifier. An adversarial input attempting to inject XML via the progId attribute.","solutions":["Remove or replace invalid characters: use only letters, digits, '.', '_', and '-'.","Replace spaces with underscores or dots (e.g. 'My_ProgId' or 'My.ProgId').","Strip XML-unsafe characters (<, >, &, \", ') entirely from the progId.","Use a standard Office progId which is guaranteed to be clean."],"exampleFix":"// before — contains spaces and special chars\nadd ole src=file.pdf progId='My App & Doc' path='/body'\n\n// after — clean progId with only allowed chars\nadd ole src=file.pdf progId=MyApp.Doc path='/body'","handlingStrategy":"validation","validationCode":"// Pre-validate progId character set\nif (!string.IsNullOrEmpty(progId))\n{\n    foreach (char ch in progId)\n    {\n        if (!(char.IsLetterOrDigit(ch) || ch == '.' || ch == '_' || ch == '-'))\n        {\n            Console.Error.WriteLine($\"progId '{progId}' contains invalid char '{ch}'. Only letters, digits, '.', '_', '-' allowed.\");\n            // Sanitize: replace invalid chars with '_'\n            progId = new string(progId.Select(c => (char.IsLetterOrDigit(c) || c=='.'||c=='_'||c=='-') ? c : '_').ToArray());\n            break;\n        }\n    }\n}\nOleHelper.ValidateProgId(progId);","typeGuard":null,"tryCatchPattern":"try\n{\n    OleHelper.ValidateProgId(progId);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"invalid characters\"))\n{\n    // Sanitize: replace invalid chars with '_' and retry\n    progId = new string(progId.Select(c => (char.IsLetterOrDigit(c) || c=='.'||c=='_'||c=='-') ? c : '_').ToArray());\n    OleHelper.ValidateProgId(progId);\n}","preventionTips":["Construct progIds from only letters, digits, '.', '_', and '-'.","When deriving progIds from filenames or user input, sanitize by replacing invalid characters with '_' or '.'.","Avoid spaces, XML-unsafe characters (<, >, &, \", '), and other punctuation in progIds.","Use standard Office progIds (which are always clean) when a custom identifier isn't required."],"tags":["ole","progid","com-validation","character-validation","xml-safety","argument-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}