iOfficeAI/OfficeCLI · error · ArgumentException

progId '{progId}' cannot start with a digit.

Error message

progId '{progId}' cannot start with a digit.

What it means

Thrown by OleHelper.ValidateProgId when a non-empty progId string starts with a digit (0-9). The Windows COM specification explicitly forbids ProgIDs that begin with a digit. Writing such a progId into the OOXML attribute would produce an OLE element that Office cannot activate or may silently misbehave on. The check is char.IsDigit(progId[0]) after the length check passes, so an empty string does NOT trigger this (it's allowed through as a no-op at this stage).

Source

Thrown at src/officecli/Core/OleHelper.cs:495

    public const long DefaultOleWidthEmu = 1828800;  // 2 inches
    public const long DefaultOleHeightEmu = 685800;   //  0.75 inches

    /// <summary>
    /// Validate a COM ProgID string against the well-known Windows COM
    /// constraints: the identifier must be 1..39 characters long and must
    /// not start with a digit. OLE spec (MSDN "ProgID") is explicit on both
    /// rules. Handlers previously accepted arbitrary strings silently; this
    /// method gives users an early, actionable error instead of writing an
    /// invalid OLE element that Office refuses to open.
    /// </summary>
    public static void ValidateProgId(string progId)
    {
        if (progId == null) return;
        if (progId.Length > 39)
            throw new ArgumentException(
                $"progId '{progId}' exceeds 39 characters (limit: 39, actual: {progId.Length}).");
        if (progId.Length > 0 && char.IsDigit(progId[0]))
            throw new ArgumentException(
                $"progId '{progId}' cannot start with a digit.");
        // COM ProgID character set: letters, digits, '.', '_', '-'. Anything
        // else (notably XML-unsafe characters like '<', '>', '&', '"') would
        // either corrupt the OOXML progId attribute or be rejected by Office
        // on reopen. Reject early with an actionable error instead of letting
        // bad bytes land in the package.
        foreach (var ch in progId)
        {
            if (!(char.IsLetterOrDigit(ch) || ch == '.' || ch == '_' || ch == '-'))
                throw new ArgumentException(
                    $"progId '{progId}' contains invalid characters. Only letters, digits, '.', '_', '-' are allowed.");
        }
    }

    /// <summary>
    /// Normalize and validate the caller-supplied <c>display</c> property
    /// for an OLE object. Canonical values are <c>"icon"</c> (show the file
    /// as a clickable icon preview) and <c>"content"</c> (show the embedded

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Start the progId with a letter instead of a digit (e.g. 'App2Doc' instead of '2AppDoc').
  2. Use a standard Office progId (which always starts with a letter: 'Word.Document.12', 'Excel.Sheet.12', etc.).
  3. Prefix a digit-starting identifier with a letter (e.g. 'D' + originalName).

Example fix

// before — progId starts with digit
add ole src=file.pdf progId=2PdfHandler path='/body'

// after — starts with a letter
add ole src=file.pdf progId=Pdf2Handler path='/body'
// or use a standard progId
add ole src=file.pdf progId=Package path='/body'
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate progId does not start with a digit
if (!string.IsNullOrEmpty(progId) && char.IsDigit(progId[0]))
{
    Console.Error.WriteLine($"progId '{progId}' cannot start with a digit. Prefix with a letter.");
    progId = "D" + progId; // or use a standard progId
}
OleHelper.ValidateProgId(progId);

Try / catch

try
{
    OleHelper.ValidateProgId(progId);
}
catch (ArgumentException ex) when (ex.Message.Contains("cannot start with a digit"))
{
    progId = "A" + progId;
    OleHelper.ValidateProgId(progId);
}

Prevention

When it happens

Trigger: Calling Add ole or Set ole with a progId like '123Doc', '2pdf', or '4MyApp'. The first character is checked with char.IsDigit, so any Unicode digit (not just ASCII 0-9) triggers it. ValidateProgId is invoked from ResolveProgId in all three handlers.

Common situations: A user who starts a custom progId with a number. A progId auto-generated from a filename that starts with a digit (e.g. '2024report.pdf' → progId '2024report'). A copy-paste error where a version number was prepended to a progId.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/dd860fa4fc8cef19. Report an issue: GitHub.