{"record":{"id":"b45d5a1c2899b071","repo":"apache/druid","slug":"failed-to-delete-google-cloud-storage-object-from","errorCode":null,"errorMessage":"Failed to delete google cloud storage object from bucket [%s] and path [%s].","messagePattern":"Failed to delete google cloud storage object from bucket \\[(.+?)\\] and path \\[(.+?)\\]\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":500,"severity":"error","filePath":"extensions-core/google-extensions/src/main/java/org/apache/druid/storage/google/GoogleDataSegmentKiller.java","lineNumber":89,"sourceCode":"    }\n    catch (StorageException e) {\n      throw new SegmentLoadingException(e, \"Couldn't kill segment[%s]: [%s]\", segment.getId(), e.getMessage());\n    }\n  }\n\n  private void deleteIfPresent(String bucket, String path)\n  {\n    try {\n      GoogleUtils.retryGoogleCloudStorageOperation(() -> {\n        storage.delete(bucket, path);\n        return null;\n      });\n    }\n    catch (StorageException e) {\n      throw e;\n    }\n    catch (Exception e) {\n      throw new RE(e, \"Failed to delete google cloud storage object from bucket [%s] and path [%s].\", bucket, path);\n    }\n  }\n\n  @Override\n  public void killAll() throws IOException\n  {\n    if (accountConfig.getBucket() == null || accountConfig.getPrefix() == null) {\n      throw new ISE(\n          \"Cannot delete all segment files from Google Deep Storage since druid.google.bucket and druid.google.prefix are not both set.\");\n    }\n    LOG.info(\n        \"Deleting all segment files from gs location [bucket: '%s' prefix: '%s']\",\n        accountConfig.getBucket(),\n        accountConfig.getPrefix()\n    );\n    try {\n      GoogleUtils.deleteObjectsInPath(\n          storage,","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/google-extensions/src/main/java/org/apache/druid/storage/google/GoogleDataSegmentKiller.java#L71-L107","documentation":"GoogleDataSegmentKiller.deleteIfPresent checks whether a GCS object exists and deletes it. StorageExceptions are deliberately rethrown so callers can apply retry semantics, but any other unexpected exception (e.g. InvalidRequest, client-side errors) is wrapped in a RuntimeException with the bucket and path for diagnosis.","triggerScenarios":"kill() calling deleteIfPresent for index.json or descriptor.json when the GCS client throws a non-StorageException error, e.g. IllegalArgumentException from an invalid object name, or an unchecked error from the response processing (blob.getResponse() handling).","commonSituations":"Segment paths containing characters GCS rejects; corrupted segment metadata producing malformed paths; bugs in custom retry/listener code around the GCS client.","solutions":["Check the wrapped cause (e.getCause()) to find the real client-side error","Validate segment object paths are well-formed GCS object names","Confirm StorageException handling covers the transient case you expected (it is rethrown, not wrapped)","Fix segment metadata if the stored path is malformed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure object name is valid GCS key before delete\nif (path.startsWith(\"/\") || path.contains(\"//\")) throw new IllegalArgumentException(\"malformed GCS path: \" + path);","typeGuard":null,"tryCatchPattern":"try { killer.kill(segment); } catch (RuntimeException e) { LOGGER.error(e.getCause(), \"deleteIfPresent failed for bucket/path\"); throw e; }","preventionTips":["Validate segment object paths when producing metadata","Inspect getCause() for non-StorageException client errors","Keep segment paths free of illegal GCS characters"],"tags":["google-cloud-storage","object-delete","apache-druid"],"backgroundTag":"gcs-delete-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}