{"record":{"id":"33eff4c3be12155a","repo":"ToolJet/ToolJet","slug":"could-not-fetch-tables-33eff4","errorCode":null,"errorMessage":"Could not fetch tables","messagePattern":"Could not fetch tables","errorType":"exception","errorClass":"QueryError","httpStatus":null,"severity":"error","filePath":"plugins/packages/dynamodb/lib/index.ts","lineNumber":165,"sourceCode":"    throw new QueryError('Method not found', `Method '${methodName}' is not supported by the DynamoDB plugin`, {});\n  }\n\n  private async _listAllTables(\n    client: DynamoDBClient,\n    args?: any\n  ): Promise<{ items: Array<{ value: string; label: string }>; totalCount: number }> {\n    const tables: string[] = [];\n    let lastEvaluatedTableName: string | undefined;\n\n    try {\n      do {\n        const command = new ListTablesCommand({ ExclusiveStartTableName: lastEvaluatedTableName, Limit: 100 });\n        const data = await client.send(command);\n        tables.push(...(data.TableNames || []));\n        lastEvaluatedTableName = data.LastEvaluatedTableName;\n      } while (lastEvaluatedTableName);\n    } catch (err) {\n      throw new QueryError('Could not fetch tables', err.message, {});\n    }\n\n    const search = (args?.search || '').toLowerCase();\n    const filtered = search ? tables.filter((name) => name.toLowerCase().includes(search)) : tables;\n\n    const page = args?.page || 1;\n    const limit = args?.limit;\n\n    if (limit) {\n      const start = (page - 1) * limit;\n      return {\n        items: filtered.slice(start, start + limit).map((name) => ({ value: name, label: name })),\n        totalCount: filtered.length,\n      };\n    }\n\n    return {\n      items: filtered.map((name) => ({ value: name, label: name })),","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/ToolJet/ToolJet/blob/20602a8e101f2e59686c9afde0d1402aac2c8871/plugins/packages/dynamodb/lib/index.ts#L147-L183","documentation":"Thrown by _listAllTables (the backing implementation of invokeMethod('listTables')) when the AWS SDK's ListTablesCommand.send rejects inside the pagination loop. The loop pages through all table names using LastEvaluatedTableName with a Limit of 100, so any send failure — on any page — aborts and is wrapped as 'Could not fetch tables'. This feeds the table-picker dropdown in the editor.","triggerScenarios":"The configured IAM principal lacks dynamodb:ListTables on the account/global resource. Network failure or STS/region misconfiguration reaching the DynamoDB endpoint. Throttling from excessive ListTables calls. An instance-profile or assumed-role credential that expired mid-iteration. The region in sourceOptions points at a region with no access.","commonSituations":"Datasource created with an IAM user that has table-level grants but not the account-level ListTables permission. EC2 instance profile credentials rotated/expired. Wrong region selected so the endpoint is unreachable or returns AccessDenied. Heavy concurrent editing sessions hammering ListTables.","solutions":["Grant the credential's principal dynamodb:ListTables on '*' (or at minimum the account scope) — this action is account-scoped, not table-scoped.","Verify the region in the datasource config is the region where your tables live.","If using instance-profile or ARN-role credentials, confirm the role trust policy and session are still valid (re-test the connection).","Read the wrapped err.message for the specific AWS error code (AccessDeniedException vs. ThrottlingException) and act on it."],"exampleFix":"// before — IAM policy missing ListTables\n{\n  \"Effect\": \"Allow\",\n  \"Action\": [\"dynamodb:GetItem\", \"dynamodb:PutItem\"],\n  \"Resource\": \"arn:aws:dynamodb:us-east-1:123:table/*\"\n}\n// after — add account-scoped ListTables\n{\n  \"Effect\": \"Allow\",\n  \"Action\": [\"dynamodb:ListTables\"],\n  \"Resource\": \"*\"\n}","handlingStrategy":"try-catch","validationCode":"// Verify IAM has ListTables before opening the picker\n// (no in-process validation; this is a server-side permission check)","typeGuard":null,"tryCatchPattern":"try { await plugin.invokeMethod('listTables', ctx, sourceOptions, args); }\ncatch (e) { if (e instanceof QueryError && e.message === 'Could not fetch tables') { /* show 'check dynamodb:ListTables permission' */ } else throw e; }","preventionTips":["Grant dynamodb:ListTables on '*' for the datasource principal.","Confirm the configured region is reachable and correct.","Cache the table list to avoid repeated ListTables calls."],"tags":["dynamodb","list-tables","iam","aws-permissions","tooljet"],"backgroundTag":null,"analyzedSha":"20602a8e101f2e59686c9afde0d1402aac2c8871","analyzedAt":"2026-08-13T05:58:54.221Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}