{"record":{"id":"aced31f8db3b2d5c","repo":"apache/iceberg","slug":"not-authorized-to-call-the-bigquery-api-or-access","errorCode":null,"errorMessage":"Not authorized to call the BigQuery API or access this resource: %s","messagePattern":"Not authorized to call the BigQuery API or access this resource: (.+?)","errorType":"exception","errorClass":"NotAuthorizedException","httpStatus":401,"severity":"error","filePath":"bigquery/src/main/java/org/apache/iceberg/gcp/bigquery/BigQueryMetastoreClientImpl.java","lineNumber":608,"sourceCode":"  /**\n   * Converts BigQuery generic API errors to Iceberg exceptions, *without* handling the\n   * resource-specific exceptions like NoSuchTableException, NoSuchNamespaceException, etc.\n   */\n  private static HttpResponse convertExceptionIfUnsuccessful(HttpResponse response)\n      throws IOException {\n    if (response.isSuccessStatusCode()) {\n      return response;\n    }\n\n    GoogleJsonResponseException exception =\n        GoogleJsonResponseException.from(GsonFactory.getDefaultInstance(), response);\n    String errorMessage =\n        exception.getStatusMessage()\n            + (exception.getContent() != null ? \"\\n\" + exception.getContent() : \"\");\n\n    switch (response.getStatusCode()) {\n      case HttpStatusCodes.STATUS_CODE_UNAUTHORIZED ->\n          throw new NotAuthorizedException(\n              \"Not authorized to call the BigQuery API or access this resource: %s\", errorMessage);\n      case HttpStatusCodes.STATUS_CODE_BAD_REQUEST -> {\n        GoogleJsonError errorDetails = exception.getDetails();\n        if (errorDetails != null) {\n          List<GoogleJsonError.ErrorInfo> errors = errorDetails.getErrors();\n          if (errors != null) {\n            for (GoogleJsonError.ErrorInfo errorInfo : errors) {\n              if (errorInfo.getReason().equals(\"resourceInUse\")) {\n                throw new NamespaceNotEmptyException(\"%s\", errorInfo.getMessage());\n              }\n            }\n          }\n        }\n        throw new BadRequestException(\"%s\", errorMessage);\n      }\n      case HttpStatusCodes.STATUS_CODE_FORBIDDEN ->\n          throw new ForbiddenException(\"%s\", errorMessage);\n      case HttpStatusCodes.STATUS_CODE_PRECONDITION_FAILED ->","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/bigquery/src/main/java/org/apache/iceberg/gcp/bigquery/BigQueryMetastoreClientImpl.java#L590-L626","documentation":"convertExceptionIfUnsuccessful maps HTTP 401 responses from the BigQuery API to NotAuthorizedException. The BigQuery client call succeeded at the transport level but Google rejected the request because the caller is not authenticated or not authorized to access the dataset/table resource.","triggerScenarios":"Any BigQueryMetastoreClientImpl call (internalCreate, load, delete, result, internalUpdate) where the underlying HTTP request returns status 401 — expired/missing OAuth credentials, a service account lacking BigQuery permissions on the dataset, or the default credentials not being picked up.","commonSituations":"Expired GOOGLE_APPLICATION_CREDENTIALS token; service account without roles/bigquery.dataOwner or dataEditor on the dataset; running locally without `gcloud auth application-default login`; wrong project configured.","solutions":["Re-authenticate: run `gcloud auth application-default login` or refresh the service-account key used via GOOGLE_APPLICATION_CREDENTIALS","Grant the caller (service account or user) BigQuery IAM permissions (e.g. roles/bigquery.dataEditor) on the target dataset/project","Verify the configured project matches the project where the credentials are valid"],"exampleFix":"// before\n// no credentials configured\nBigQueryMetastoreCatalog catalog = new BigQueryMetastoreCatalog();\n// after\n// export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa-key.json\n// grant roles/bigquery.dataEditor to the SA on the dataset\ncatalog.initialize(\"bq\", conf);","handlingStrategy":"try-catch","validationCode":"// Java: verify credentials resolve before building the catalog\nGoogleCredentials creds = GoogleCredentials.getApplicationDefault();\nPreconditions.checkNotNull(creds, \"No GCP credentials found\");","typeGuard":null,"tryCatchPattern":"try {\n  Table t = catalog.loadTable(id);\n} catch (NotAuthorizedException e) {\n  LOG.error(\"BigQuery auth failed; check credentials/IAM for {}\", id, e);\n  throw e;\n}","preventionTips":["Set GOOGLE_APPLICATION_CREDENTIALS explicitly in every environment","Grant the service account roles/bigquery.dataEditor on the target datasets","Refresh tokens before long-running jobs; avoid expired key files","Test authentication with `bq ls` using the same identity before running jobs"],"tags":["bigquery","authentication","authorization","http-401"],"backgroundTag":"permission-denied","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}