Skip to content

validateManifest: false-positive "must NOT have additional properties" (builtInGroupId, overriddenByRibbonApi) for ribbon groups on a built-in tab (builtInTabId) #997

@kachkaev

Description

@kachkaev

Expected behavior

validateManifest (and office-addin-manifest validate) should report a unified (JSON) manifest as valid when a ribbon button is added to a built-in tab using ribbons[].tabs[].builtInTabId (e.g. "TabHome") together with a custom group that declares id, label, and controls.

This is the documented structure for adding a custom button to a built-in tab, the TeamsManifestV1D25 typings allow builtInTabId on the tab, and Office renders the button correctly from this manifest.

Current behavior

validateManifest returns isValid: false with two errors, even though the group declares neither of the named properties:

/extensions/0/ribbons/0/tabs/0/groups/0 must NOT have additional properties. Details: {"additionalProperty":"builtInGroupId"}
/extensions/0/ribbons/0/tabs/0/groups/0 must NOT have additional properties. Details: {"additionalProperty":"overriddenByRibbonApi"}

The group in the input manifest only contains controls, icons, id, and label. builtInGroupId and overriddenByRibbonApi are never declared — they appear to be injected during conversion and then rejected by the schema applied to groups under a builtInTabId tab.

Observations:

  • Reproduces for every group shape under builtInTabId — with or without group icons, and even a minimal { id, label, controls } group.
  • Removing builtInTabId (e.g. switching to a custom tab with id + label + position) makes validation pass — but then the button cannot be anchored to a built-in tab such as Home, so this isn't a viable workaround for the documented scenario.
  • Net effect: there is no way to validate a manifest that puts a custom ribbon button on a built-in tab, despite that being the documented and runtime-correct structure.

The relevant tab/group (the only part that matters for the repro):

{
  "builtInTabId": "TabHome",
  "groups": [
    {
      "id": "ContosoCommandsGroup",
      "label": "Contoso",
      "icons": [
        { "size": 16, "url": "https://contoso.com/assets/icon-16.png" },
        { "size": 32, "url": "https://contoso.com/assets/icon-32.png" },
        { "size": 80, "url": "https://contoso.com/assets/icon-80.png" }
      ],
      "controls": [
        {
          "id": "ContosoTaskpaneButton",
          "type": "button",
          "label": "Open Contoso",
          "actionId": "OpenTaskPane",
          "enabled": true,
          "icons": [
            { "size": 16, "url": "https://contoso.com/assets/icon-16.png" },
            { "size": 32, "url": "https://contoso.com/assets/icon-32.png" },
            { "size": 80, "url": "https://contoso.com/assets/icon-80.png" }
          ],
          "supertip": { "title": "Open Contoso", "description": "Open the Contoso task pane" }
        }
      ]
    }
  ]
}

Steps to Reproduce

  1. Save the full manifest below as manifest.json (a minimal Excel task pane unified manifest whose single ribbon tab targets the built-in Home tab via builtInTabId: "TabHome").
  2. Validate it:
    npx office-addin-manifest validate manifest.json
    (or call validateManifest("manifest.json") from office-addin-manifest.)
  3. Validation fails with isValid: false and the two must NOT have additional properties errors shown above, even though neither builtInGroupId nor overriddenByRibbonApi is present in the manifest.
Full minimal manifest.json
{
  "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.25/MicrosoftTeams.schema.json",
  "manifestVersion": "1.25",
  "id": "00000000-0000-0000-0000-000000000000",
  "version": "1.0.0",
  "name": { "short": "Contoso Excel", "full": "Contoso Excel Add-in" },
  "description": {
    "short": "A minimal Contoso task pane add-in.",
    "full": "A minimal Contoso task pane add-in that anchors a ribbon button to the Home tab."
  },
  "developer": {
    "name": "Contoso",
    "websiteUrl": "https://contoso.com",
    "privacyUrl": "https://contoso.com",
    "termsOfUseUrl": "https://contoso.com"
  },
  "icons": { "color": "assets/color.png", "outline": "assets/outline.png" },
  "accentColor": "#338080",
  "validDomains": ["contoso.com"],
  "showLoadingIndicator": false,
  "isFullScreen": false,
  "defaultBlockUntilAdminAction": false,
  "localizationInfo": { "defaultLanguageTag": "en-us", "additionalLanguages": [] },
  "authorization": {
    "permissions": {
      "resourceSpecific": [{ "name": "Document.ReadWrite.User", "type": "Delegated" }]
    }
  },
  "extensions": [
    {
      "requirements": { "scopes": ["workbook"] },
      "getStartedMessages": [
        {
          "title": "Contoso Excel add-in loaded",
          "description": "Go to the Home tab and open the Contoso task pane.",
          "learnMoreUrl": "https://contoso.com",
          "requirements": { "formFactors": ["desktop"], "scopes": ["workbook"] }
        }
      ],
      "alternates": [
        {
          "alternateIcons": {
            "icon": { "size": 32, "url": "https://contoso.com/assets/icon-32.png" },
            "highResolutionIcon": { "size": 64, "url": "https://contoso.com/assets/icon-64.png" }
          }
        }
      ],
      "ribbons": [
        {
          "contexts": ["default"],
          "requirements": {
            "capabilities": [{ "name": "AddinCommands", "minVersion": "1.1" }],
            "formFactors": ["desktop"],
            "scopes": ["workbook"]
          },
          "tabs": [
            {
              "builtInTabId": "TabHome",
              "groups": [
                {
                  "id": "ContosoCommandsGroup",
                  "label": "Contoso",
                  "icons": [
                    { "size": 16, "url": "https://contoso.com/assets/icon-16.png" },
                    { "size": 32, "url": "https://contoso.com/assets/icon-32.png" },
                    { "size": 80, "url": "https://contoso.com/assets/icon-80.png" }
                  ],
                  "controls": [
                    {
                      "id": "ContosoTaskpaneButton",
                      "type": "button",
                      "label": "Open Contoso",
                      "actionId": "OpenTaskPane",
                      "enabled": true,
                      "icons": [
                        { "size": 16, "url": "https://contoso.com/assets/icon-16.png" },
                        { "size": 32, "url": "https://contoso.com/assets/icon-32.png" },
                        { "size": 80, "url": "https://contoso.com/assets/icon-80.png" }
                      ],
                      "supertip": { "title": "Open Contoso", "description": "Open the Contoso task pane" }
                    }
                  ]
                }
              ]
            }
          ],
          "runtimes": [
            {
              "id": "TaskPaneRuntime",
              "type": "general",
              "lifetime": "short",
              "code": { "page": "https://contoso.com/taskpane" },
              "actions": [{ "id": "OpenTaskPane", "type": "openPage" }],
              "requirements": {
                "capabilities": [{ "name": "AddinCommands", "minVersion": "1.1" }],
                "formFactors": ["desktop"]
              }
            }
          ]
        }
      ]
    }
  ]
}

Context

  • Operating System: reproduces regardless of OS (validation is static); observed on macOS.
  • Node version: v24.15.0
  • Office version: N/A — the manifest is validated statically, not against an installed Office build.
  • Tool version: office-addin-manifest 2.1.5 (latest at time of filing)

Failure Logs

$ npx office-addin-manifest validate manifest.json

/extensions/0/ribbons/0/tabs/0/groups/0 must NOT have additional properties. Details: {"additionalProperty":"builtInGroupId"}
/extensions/0/ribbons/0/tabs/0/groups/0 must NOT have additional properties. Details: {"additionalProperty":"overriddenByRibbonApi"}

The manifest only declares controls, icons, id, and label on the group; builtInGroupId / overriddenByRibbonApi are reported as disallowed additional properties despite never being present in the input, which points to them being injected during the JSON-manifest conversion and then failing the group schema selected for a builtInTabId tab.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions