apache/druid · error · IOException

IOException wrapping underlying cause

Error message

IOException wrapping underlying cause

What it means

buildInputParams determines the blob size via azureStorage.getBlockBlobLength and wraps BlobStorageException in an IOException. It is thrown when the Azure service rejects the metadata/properties request for the blob at the given path — most commonly because the blob does not exist or the credentials lack read access.

Source

Thrown at extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/output/AzureStorageConnector.java:68

  private final AzureStorage azureStorage;

  public AzureStorageConnector(
      final AzureOutputConfig config,
      final AzureStorage azureStorage
  )
  {
    this.config = config;
    this.azureStorage = azureStorage;
  }

  @Override
  public ChunkingStorageConnectorParameters<AzureInputRange> buildInputParams(String path) throws IOException
  {
    try {
      return buildInputParams(path, 0, azureStorage.getBlockBlobLength(config.getContainer(), objectPath(path)));
    }
    catch (BlobStorageException e) {
      throw new IOException(e);
    }
  }

  @Override
  public ChunkingStorageConnectorParameters<AzureInputRange> buildInputParams(String path, long from, long size)
  {
    ChunkingStorageConnectorParameters.Builder<AzureInputRange> parameters = new ChunkingStorageConnectorParameters.Builder<>();
    parameters.tempDirSupplier(config::getTempDir);
    parameters.maxRetry(config.getMaxRetry());
    parameters.cloudStoragePath(objectPath(path));
    parameters.retryCondition(AzureUtils.AZURE_RETRY);
    parameters.start(from);
    parameters.end(from + size);
    parameters.objectSupplier((start, end) -> new AzureInputRange(
        start,
        end - start,
        config.getContainer(),
        objectPath(path)

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Verify the blob path exists: az storage blob exists --container-name <c> --name <objectPath>; fix the path/container/prefix config if wrong
  2. Validate credentials grant read/get-properties on the container if the status code is 403
  3. Check the BlobStorageException status code in the IOException cause for 4xx vs 5xx and retry on 5xx/transient errors
  4. If this occurs during ingestion, confirm the segments were successfully published to Azure deep storage first

Example fix

// before
params = connector.buildInputParams("unknown/path.json");
// after
if (connector.pathExists("unknown/path.json")) {
  params = connector.buildInputParams("unknown/path.json");
} else {
  throw new ISE("Path %s does not exist in Azure container", "unknown/path.json");
}
Defensive patterns

Strategy: validation

Validate before calling

if (!connector.pathExists(path)) { throw new IllegalArgumentException("Blob not found: " + path); }
// then call buildInputParams(path) safely for 404 cases

Try / catch

try { params = connector.buildInputParams(path); } catch (IOException e) { BlobStorageException b = findCause(e, BlobStorageException.class); if (b != null && b.getStatusCode() == 404) handleMissing(path); else throw e; }

Prevention

When it happens

Trigger: Calling buildInputParams(path) on AzureStorageConnector for a path whose getBlockBlobLength call returns a BlobStorageException: 404 blob not found, 403 auth failure, or 5xx service error while resolving container+objectPath.

Common situations: Deep storage path typos or wrong druid.storage.container/prefix so the object path does not exist; firehose/input-source setup pointing at segments not yet published; SAS/key without get-blob-properties permission; transient Azure outages.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/6f1d6a53c672be87. Report an issue: GitHub.