apache/hadoop · error · RuntimeException

Object %s doesn't exit

Error message

Object %s doesn't exit

What it means

TOS.get(key, offset, limit) special-cases limit == 0: a zero-byte range GET would not reveal whether the object exists, so it calls head(key) instead; if the object does not exist it throws RuntimeException("Object <key> doesn't exit") (the message contains a typo of 'exist'). A zero-length read of a missing object is thereby converted into a not-found error.

Source

Thrown at hadoop-cloud-storage-project/hadoop-tos/src/main/java/org/apache/hadoop/fs/tosfs/object/tos/TOS.java:252

    this.client = client;
  }

  private void checkAvailableClient() {
    Preconditions.checkState(client != null,
        "Encountered uninitialized ObjectStorage, call initialize(..) please.");
  }

  @Override
  public ObjectContent get(String key, long offset, long limit) {
    checkAvailableClient();
    Preconditions.checkArgument(offset >= 0, "offset is a negative number: %s", offset);

    if (limit == 0) {
      // Can not return empty stream when limit = 0, because the requested object might not exist.
      if (head(key) != null) {
        return new ObjectContent(Constants.MAGIC_CHECKSUM, EMPTY_STREAM);
      } else {
        throw new RuntimeException(String.format("Object %s doesn't exit", key));
      }
    }

    long end = limit < 0 ? -1 : offset + limit - 1;
    GetObjectFactory factory = (k, startOff, endOff) -> getObject(key, startOff, endOff);
    ChainTOSInputStream chainStream =
        new ChainTOSInputStream(factory, key, offset, end, maxDrainBytes, maxInputStreamRetries);
    return new ObjectContent(chainStream.checksum(), chainStream);
  }

  @Override
  public Iterable<ObjectInfo> listDir(String key, boolean recursive) {
    if (recursive) {
      if (bucket().isDirectory()) {
        // The directory bucket only support list object with delimiter = '/', so if we want to
        // list directory recursively, we have to list each dir step by step.
        return bfsListDir(key);
      } else {

View on GitHub (pinned to 2add963021)

Solutions

  1. Check objectStatus/head(key) before get(key, offset, 0) and handle a null result
  2. Catch this RuntimeException and map it to FileNotFoundException for proper Hadoop semantics
  3. Remove the concurrent delete/read race, or accept the failure as a benign not-found signal

Example fix

// before
ObjectContent c = storage.get(key, 0, 0);

// after
if (storage.head(key) == null) {
  throw new FileNotFoundException(key);
}
ObjectContent c = storage.get(key, 0, 0);
Defensive patterns

Strategy: validation

Validate before calling

if (storage.head(key) == null) {
  throw new FileNotFoundException(key);
}
ObjectContent c = storage.get(key, offset, 0);

Try / catch

try {
  return storage.get(key, 0, 0);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().contains("doesn't exit")) {
    throw (FileNotFoundException) new FileNotFoundException(key).initCause(e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Reading an object with limit 0 — e.g. an empty-file read or a length-0 verification — when the key does not exist: deleted concurrently, wrong key/prefix, or a key that was never written.

Common situations: A concurrent delete racing a zero-length read; stale file-status caches claiming a file exists after removal; keys assembled with the wrong prefix or encoding.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/26699b9f6ecb7f5e. Report an issue: GitHub.