Budibase/budibase · error · Error

You must set a spreadsheet ID in your configuration to fetch

Error message

You must set a spreadsheet ID in your configuration to fetch tables.

What it means

cleanSpreadsheetUrl normalises either a full Google Sheets URL or a bare spreadsheet ID into a spreadsheet ID. If the configured spreadsheetId is empty/undefined there is nothing to parse and no sheet can be reached, so the constructor throws before any API call is made.

Source

Thrown at packages/server/src/integrations/googlesheets.ts:199

    }
  }

  getBindingIdentifier() {
    return ""
  }

  getStringConcat(_parts: string[]) {
    return ""
  }

  /**
   * Pull the spreadsheet ID out from a valid google sheets URL
   * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
   * @returns spreadsheet Id of the google sheet
   */
  private cleanSpreadsheetUrl(spreadsheetId: string) {
    if (!spreadsheetId) {
      throw new Error(
        "You must set a spreadsheet ID in your configuration to fetch tables."
      )
    }
    const parts = spreadsheetId.split("/")
    return parts.length > 5 ? parts[5] : spreadsheetId
  }

  private async fetchAccessToken(
    payload: AuthTokenRequest
  ): Promise<AuthTokenResponse> {
    const response = await fetch("https://www.googleapis.com/oauth2/v4/token", {
      method: "POST",
      body: JSON.stringify({
        ...payload,
        grant_type: "refresh_token",
      }),
      headers: {
        "Content-Type": "application/json",

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Open the Google Sheets datasource and select/paste a spreadsheet URL or ID, then re-fetch tables
  2. Verify the saved datasource entity actually has a non-empty spreadsheetId property
  3. If passing a URL, confirm it is a valid sheets URL (cleanSpreadsheetUrl splits on '/' and reads parts[5])
  4. Guard calling code (testConnection/buildSchema) so it does not run until spreadsheetId is set

Example fix

// before
const ds = { type: 'GOOGLE_SHEETS', accessToken: token, spreadsheetId: undefined }
new GoogleSheetsIntegration(ds) // throws
// after
const ds = { type: 'GOOGLE_SHEETS', accessToken: token, spreadsheetId: 'https://docs.google.com/spreadsheets/d/1AbC.../edit' }
new GoogleSheetsIntegration(ds)
Defensive patterns

Strategy: validation

Validate before calling

function validateGSheetsConfig(config) {
  if (!config.spreadsheetId || typeof config.spreadsheetId !== 'string') {
    throw new Error('Google Sheets datasource requires a spreadsheetId or sheet URL')
  }
}

Type guard

function hasSpreadsheetId(config) {
  return typeof config?.spreadsheetId === 'string' && config.spreadsheetId.trim().length > 0
}

Try / catch

try {
  const integration = new GoogleSheetsIntegration(config)
} catch (err) {
  if (err.message.includes('You must set a spreadsheet ID')) {
    // redirect user to select a spreadsheet in the datasource UI
  } else throw err
}

Prevention

When it happens

Trigger: Instantiating GoogleSheetsIntegration (constructor → cleanSpreadsheetUrl) with config.spreadsheetId undefined/null/empty string — typically when table fetching is triggered on a datasource that never had a spreadsheet selected.

Common situations: Datasource created via OAuth but the user never picked a spreadsheet; spreadsheetId field cleared after saving; fetching table names on a partially configured datasource; automation or script calling buildSchema without the spreadsheetId field.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/5f01ffd3fd304367. Report an issue: GitHub.