{"record":{"id":"164b7bfae73ed389","repo":"apache/druid","slug":"ioexception-wrapping-underlying-cause-164b7b","errorCode":null,"errorMessage":"IOException wrapping underlying cause","messagePattern":"IOException wrapping underlying cause","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureTaskLogs.java","lineNumber":161,"sourceCode":"      try {\n        final long start;\n        final long length = azureStorage.getBlockBlobLength(container, taskKey);\n\n        if (offset > 0 && offset < length) {\n          start = offset;\n        } else if (offset < 0 && (-1 * offset) < length) {\n          start = length + offset;\n        } else {\n          start = 0;\n        }\n\n        InputStream stream = azureStorage.getBlockBlobInputStream(container, taskKey);\n        stream.skip(start);\n\n        return Optional.of(stream);\n      }\n      catch (Exception e) {\n        throw new IOException(e);\n      }\n    }\n    catch (BlobStorageException e) {\n      throw new IOE(e, \"Failed to stream logs from: %s\", taskKey);\n    }\n  }\n\n  private String getTaskLogKey(String taskid)\n  {\n    return StringUtils.format(\"%s/%s/log\", config.getPrefix(), taskid);\n  }\n\n  private String getTaskReportsKey(String taskid)\n  {\n    return StringUtils.format(\"%s/%s/report.json\", config.getPrefix(), taskid);\n  }\n\n  private String getTaskStatusKey(String taskid)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureTaskLogs.java#L143-L179","documentation":"streamTaskFile wraps any non-BlobStorageException failure to open a blob input stream into an IOException. It is thrown when streaming a task payload, log, report, or status file from Azure fails for reasons other than a recognized blob error — e.g., stream creation or skip() failures, network errors, or SDK client errors.","triggerScenarios":"Calling streamTaskLog/streamTaskReports/streamTaskStatus/streamTaskPayload when azureStorage.getBlockBlobInputStream throws a generic Exception (network failure, SDK error, interrupted stream setup, or skip(start) failure), distinct from the BlobStorageException branch at line 165.","commonSituations":"Transient network failures while opening the blob stream; Azure SDK client configuration problems; requesting an invalid byte range via skip() on a short stream; intermittent storage service errors not surfaced as BlobStorageException.","solutions":["Inspect the wrapped cause of the IOException to see the actual SDK exception","Retry the stream operation — transient network issues while opening blob streams are common","Verify the blob exists and the requested start offset is within the blob size to avoid skip() failures","Check druid.storage.container and account configuration if failures are persistent"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { Optional<InputStream> s = taskLogs.streamTaskLog(taskId, offset); } catch (IOException e) { if (isTransient(e)) retryWithBackoff(); else throw e; }","preventionTips":["Ensure requested offsets are within the blob length before streaming","Configure adequate retries in the Azure SDK client used by the extension","Treat IOExceptions with transient causes (timeouts, 5xx) as retryable, not fatal"],"tags":["azure","blob-storage","streaming","wrapper-exception"],"backgroundTag":"file-read-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}