{"record":{"id":"e3ad551f44979efe","repo":"paperclipai/paperclip","slug":"at-least-one-allowed-spreadsheet-id-is-required-e3ad55","errorCode":null,"errorMessage":"At least one allowed spreadsheet ID is required.","messagePattern":"At least one allowed spreadsheet ID is required\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/google-sheets-mcp-server/src/tools.ts","lineNumber":144,"sourceCode":"        return formatTextResponse(await execute(parsed));\n      } catch (error) {\n        return formatErrorResponse(error, options.secretRedactions ?? []);\n      }\n    },\n  };\n}\n\nfunction assertAllowed(allowedSpreadsheetIds: Set<string>, spreadsheetId: string) {\n  if (!allowedSpreadsheetIds.has(spreadsheetId)) {\n    throw new Error(`Spreadsheet ${spreadsheetId} is not in the configured allowlist.`);\n  }\n}\n\nexport function createToolDefinitions(options: GoogleSheetsToolOptions): GoogleSheetsToolDefinition[] {\n  const allowedSpreadsheetIds = Array.from(new Set(options.allowedSpreadsheetIds.map((id) => id.trim()).filter(Boolean)));\n  const allowedSpreadsheetIdSet = new Set(allowedSpreadsheetIds);\n  if (allowedSpreadsheetIds.length === 0) {\n    throw new Error(\"At least one allowed spreadsheet ID is required.\");\n  }\n\n  return [\n    makeTool(\n      options,\n      \"list_spreadsheets\",\n      \"List the Google Sheets spreadsheets configured in this connection allowlist.\",\n      \"read\",\n      z.object({}),\n      async () => options.client.listSpreadsheets(allowedSpreadsheetIds),\n    ),\n    makeTool(\n      options,\n      \"get_spreadsheet_info\",\n      \"Get spreadsheet metadata and sheet tab information for an allowlisted spreadsheet.\",\n      \"read\",\n      spreadsheetToolSchema,\n      async ({ spreadsheetId }) => {","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/google-sheets-mcp-server/src/tools.ts#L126-L162","documentation":"createToolDefinitions normalizes options.allowedSpreadsheetIds (trim + dedupe + filter(Boolean)) and refuses to build any tools if the resulting list is empty. The library treats an empty allowlist as a misconfiguration rather than a valid 'deny all' state, because it would otherwise expose tools that can never succeed.","triggerScenarios":"Starting the google-sheets MCP server with allowedSpreadsheetIds unset, empty, or filled only with whitespace/blank strings; a config loader that silently drops the field on parse failure.","commonSituations":"Missing GOOGLE_SHEETS_SPREADSHEET_IDS env var in deployment; .env file not loaded in the process running the MCP server; CI secret masking that replaces the value with an empty string.","solutions":["Set the allowed spreadsheet IDs env var (e.g. GOOGLE_SHEETS_SPREADSHEET_IDS='id1,id2') and confirm it is visible to the server process.","If constructing the config in code, pass at least one non-empty string in allowedSpreadsheetIds.","Print the resolved config at startup to confirm the value is not being stripped by a loader."],"exampleFix":"// before\ncreateToolDefinitions({ allowedSpreadsheetIds: [], client })\n// after\ncreateToolDefinitions({ allowedSpreadsheetIds: ['1Bx...'], client })","handlingStrategy":"validation","validationCode":"const ids = (process.env.GOOGLE_SHEETS_SPREADSHEET_IDS ?? '').split(',').map(s=>s.trim()).filter(Boolean);\nif (ids.length === 0) throw new Error('Set GOOGLE_SHEETS_SPREADSHEET_IDS before starting the server');\ncreateToolDefinitions({ allowedSpreadsheetIds: ids, client });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the env var at process startup with a clear error before constructing tools.","Document the required env var in your deployment manifest.","Add a startup self-check that logs the resolved allowlist length."],"tags":["configuration","startup-validation","allowlist","google-sheets-mcp"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}