{"record":{"id":"925ebb151fbc1d8d","repo":"apache/beam","slug":"more-than-d-attempts-to-call-appendrows-failed-last-925ebb","errorCode":null,"errorMessage":"More than %d attempts to call AppendRows failed. Last encountered error: %s. Please check if the destination table exists and if the service account has the bigquery.tables.updateData permission.","messagePattern":"More than (.+?) attempts to call AppendRows failed\\. Last encountered error: (.+?)\\. Please check if the destination table exists and if the service account has the bigquery\\.tables\\.updateData permission\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/StorageApiWritesShardedRecords.java","lineNumber":1086,"sourceCode":"          initializeContexts.accept(contexts);\n          try {\n            retryManager.run(true);\n          } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw e;\n          } catch (Exception e) {\n            Status.Code statusCode = Status.fromThrowable(e).getCode();\n            String errorMessage =\n                String.format(\n                    \"More than %d attempts to call AppendRows failed. Last encountered error: %s\",\n                    maxRetries, e.toString());\n            if (statusCode == Status.Code.PERMISSION_DENIED\n                || statusCode == Status.Code.NOT_FOUND) {\n              errorMessage +=\n                  \". Please check if the destination table exists and if the service account has the \"\n                      + \"bigquery.tables.updateData permission.\";\n            }\n            throw new RuntimeException(errorMessage, e);\n          }\n\n          appendSplitDistribution.update(numAppends);\n          if (autoUpdateSchema) {\n            @Nullable StreamAppendClient streamAppendClient =\n                appendClientHolder.getStreamAppendClient();\n            TableSchema originalSchema = appendClientHolder.get().getTableSchema();\n\n            @Nullable TableSchema updatedSchemaReturned =\n                (streamAppendClient != null) ? streamAppendClient.getUpdatedSchema() : null;\n            // Update the table schema and clear the append client.\n            if (updatedSchemaReturned != null) {\n              Optional<TableSchema> newSchema =\n                  TableSchemaUpdateUtils.getUpdatedSchema(originalSchema, updatedSchemaReturned);\n              if (newSchema.isPresent()) {\n                APPEND_CLIENTS.invalidate(messageConverters.getAppendClientKey(element.getKey()));\n                LOG.debug(\n                    \"Fetched updated schema for table {}:\\n\\t{}\", tableId, updatedSchemaReturned);","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/StorageApiWritesShardedRecords.java#L1068-L1104","documentation":"RuntimeException thrown by the WriteRecordsDoFn in the sharded Storage Write path after all configured attempts to call AppendRows failed. The message carries the last underlying error; PERMISSION_DENIED or NOT_FOUND statuses add a hint to check the destination table's existence and the service account's bigquery.tables.updateData permission.","triggerScenarios":"AppendRows fails on every retry for a shard's records — persistent gRPC errors such as PERMISSION_DENIED, NOT_FOUND, unavailability, or unrecoverable schema problems — until the retry counter exceeds the attempt limit.","commonSituations":"Missing bigquery.tables.updateData for the pipeline service account; destination table dropped mid-run; Storage Write API outage or quota limits; schema changed on the table so buffered rows no longer validate.","solutions":["Inspect the wrapped cause for the final gRPC status code","Grant bigquery.tables.updateData on the destination table to the pipeline service account","Verify the table exists for the full pipeline duration","Check BigQuery quotas and service health; restart from checkpoint after transient failures","Align the writer schema with the table or enable auto schema update"],"exampleFix":"// before\n// pipeline SA lacks write access -> NOT_FOUND/PERMISSION_DENIED after retries\n// after\n// grant bigquery.dataEditor on the dataset to the SA running the pipeline","handlingStrategy":"retry","validationCode":"com.google.cloud.bigquery.Table t = bigquery.getTable(tableId);\nif (t == null) throw new IllegalStateException(\"Destination table missing: \" + tableId);\n// ensure the pipeline SA has bigquery.tables.updateData (roles/bigquery.dataEditor)","typeGuard":null,"tryCatchPattern":"try {\n  pipeline.run().waitUntilFinish();\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"attempts to call AppendRows failed\")) {\n    log.error(\"AppendRows retries exhausted; cause:\", e.getCause());\n    // grant permissions / restore table / wait out outage, then resubmit\n  } else { throw e; }\n}","preventionTips":["Grant roles/bigquery.dataEditor on the dataset to the pipeline service account","Keep destination tables alive for the pipeline's lifetime","Enable schema auto-update or keep writer and table schemas in sync","Alert on BigQuery quota/service issues before they exhaust AppendRows retries"],"tags":["bigquery","storage-write","grpc","permission-denied","retry-exhausted","gcp"],"backgroundTag":"api-request-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}