Sheet protection fails with 'grid id not found' error when using Google Sheets API

I keep getting an error when trying to protect ranges in my Google Sheet

I’m working with the Google Sheets API and trying to add protected ranges to my spreadsheet. However, I keep running into this error:

HttpError 400 - “Invalid requests[0].addProtectedRange: No grid with id: 1”

Here’s my current code:

def protect_sheet_ranges(sheet_id):
    sheets_service = build_sheets_client()

    protection_requests = [
        {
            "addProtectedRange": {
                'protectedRange': {
                    "range": {
                        "sheetId": 1,
                        "startRowIndex": 0,
                        "endRowIndex": 0,
                        "startColumnIndex": 0
                    },
                    "description": "Header row protection",
                    "warningOnly": True
                }
            }
        }
    ]

    request_body = {
        'requests': protection_requests
    }
    
    result = sheets_service.spreadsheets().batchUpdate(
        spreadsheetId=sheet_id,
        body=request_body
    ).execute()

I’m not sure if this is a bug with the API or if I’m doing something wrong with the sheet ID reference. Has anyone encountered this before?

Yeah, I ran into this same problem a few weeks back. You’re using sheetId: 1, but that sheet doesn’t exist. Try sheetId: 0 instead - that’s usually the first sheet. Or call the get method on your spreadsheet first to check which sheet IDs actually exist.

Had the same problem building an automation tool for our team’s reports. Yeah, it’s the sheetId reference, but here’s what really got me - this error shows up even when the sheetId exists if you’re dealing with new sheets or someone just renamed/moved stuff around. I ended up writing a helper function that grabs current sheet properties before every protection operation. Learned this the hard way: sheetIds change when you duplicate or import sheets from other spreadsheets. If you’re using template sheets that get copied a lot, don’t hardcode the sheetId - validate it dynamically each time. Would’ve saved me hours when our template structure changed.

This happens when you’re referencing a sheetId that doesn’t exist in your spreadsheet. The sheetId isn’t the same as your spreadsheet ID - it’s Google’s internal identifier for each sheet tab. I hit this exact problem last month on a similar project. Here’s the thing: Google auto-generates these sheetId values starting from 0 for the first sheet. If you’ve hardcoded sheetId as 1, you’re probably targeting a sheet that doesn’t exist. To fix it, grab the actual sheet metadata first using spreadsheets().get() and check the sheets array in the response. Each sheet object has a properties field with the real sheetId value. Quick fix: if you’re targeting the first sheet, try changing your sheetId from 1 to 0 - the first sheet usually has ID 0.