Cannot edit XLSM file, while XLSX edits well (error 403)

Hey guys, I have an issue with my n8n workflow. The goal is to create a workflow which will edit XLSM file type. Now, it successfully works with XLSX file and edits its cells well, in both http request and excel nodes.
However, when it comes to dealing with XSLM file type, it returns “Forbidden - perhaps check your credentials” error 403. Credentials I use for XLSX and XLSM are the same, they both are in the same folder, and both are completely in OneDrive (only in cloud)

Please share your workflow

Information on your n8n setup

  • n8n version: 2.6.4
  • Database (default: SQLite): SQLite
  • Running n8n via (Docker, npm, n8n cloud, desktop app): npm
  • Operating system: Windows 11

Hello @edmondez ,
This is a known limitation of the Microsoft Graph API—it blocks write operations on .xlsm (Macro-Enabled) files to prevent corruption, which is why you get a 403 Forbidden even with correct credentials. The most reliable fix is to save your file as a standard .xlsx, which the API handles instantly without issues.
Let me know if the .xlsx conversion works for you.

Hi @edmondez ,
The Microsoft Graph Excel API doesn’t fully support .xlsm (macro-enabled) files — that’s why you get the 403. It’s a Microsoft limitation, not a credentials issue.

Simplest fix: Instead of using the Excel workbook endpoints directly, download the .xlsm file as binary, edit it in a Code node using the xlsx library, and re-upload it back to OneDrive. This bypasses the problematic /workbook/ API entirely.

Alternatively, try creating a workbook session first (POST .../workbook/createSession) and pass the workbook-session-id header in your subsequent requests — this sometimes resolves the 403 for .xlsm files.

The other replies covered the main issue, Microsoft’s Graph API just doesn’t play nice with xlsm files for writes. But if you really need to keep the macros intact and can’t convert to xlsx, the download-edit-reupload approach Msquare mentioned is probably your best path forward.

You’d grab the file as binary from OneDrive, use a Code node with the xlsx library (which does support xlsm), make your edits there, then push it back up. Something like this should get you started:

```

{

“nodes”: [

{

  "parameters": {

    "method": "GET",

    "url": "https://graph.microsoft.com/v1.0/me/drive/items/YOUR_FILE_ID/content",

    "authentication": "oAuth2",

    "options": {

      "response": {

        "response": {

          "responseFormat": "file"

        }

      }

    }

  },

  "name": "Download XLSM",

  "type": "n8n-nodes-base.httpRequest",

  "typeVersion": 4.2,

  "position": \[

    240,

    300

  \],

  "credentials": {

    "microsoftOneDriveOAuth2Api": {

      "id": "your-credential-id",

      "name": "Microsoft OneDrive"

    }

  }

},

{

  "parameters": {

    "jsCode": "const XLSX = require('xlsx');\\n\\n// Read the binary file\\nconst workbook = XLSX.read($input.first().binary.data.data, { type: 'buffer', bookType: 'xlsm' });\\n\\n// Get first sheet\\nconst sheet = workbook.Sheets\[workbook.SheetNames\[0\]\];\\n\\n// Edit cell A1\\nsheet\['A1'\] = { t: 's', v: 'Your new value' };\\n\\n// Write back to buffer\\nconst output = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsm' });\\n\\nreturn \[{ binary: { data: await this.helpers.prepareBinaryData(Buffer.from(output), 'edited.xlsm') } }\];"

  },

  "name": "Edit XLSM",

  "type": "n8n-nodes-base.code",

  "typeVersion": 2,

  "position": \[

    460,

    300

  \]

},

{

  "parameters": {

    "method": "PUT",

    "url": "https://graph.microsoft.com/v1.0/me/drive/items/YOUR_FILE_ID/content",

    "authentication": "oAuth2",

    "sendBody": true,

    "contentType": "binaryData",

    "inputDataFieldName": "data"

  },

  "name": "Upload XLSM",

  "type": "n8n-nodes-base.httpRequest",

  "typeVersion": 4.2,

  "position": \[

    680,

    300

  \],

  "credentials": {

    "microsoftOneDriveOAuth2Api": {

      "id": "your-credential-id",

      "name": "Microsoft OneDrive"

    }

  }

}

],

“connections”: {

"Download XLSM": {

  "main": \[

    \[

      {

        "node": "Edit XLSM",

        "type": "main",

        "index": 0

      }

    \]

  \]

},

"Edit XLSM": {

  "main": \[

    \[

      {

        "node": "Upload XLSM",

        "type": "main",

        "index": 0

      }

    \]

  \]

}

}

}

```

You’ll need to swap out YOUR_FILE_ID with the actual OneDrive item ID and adjust the cell editing logic in the Code node to match what you’re actually trying to do. The xlsx library preserves macros when you read/write xlsm files this way, which is the whole point since the Graph API’s workbook endpoints would strip them anyway.