> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tape.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading

Everything on Tapedrive is fetched by track address. Names resolve to tracks through listings, and everything a wallet stored is discoverable from its pubkey alone: no index to maintain, no credentials to hold. Reads need no signing.

Read capacity comes from gateways. Tapenet's hosted public tier is free and heavily
metered, fine for browsing and light traffic; real workloads use a paid gateway tier or
run their own ([rate limits](/apis/rate-limits) covers the tiers).

## Gateway reads

The everyday path. The client reads decoded tracks and objects through a gateway: one read call whether the data was written whole or as a stream (a manifest maps large files to their segments, and the client follows it for you). Rate limiting is handled for you, surfacing as a typed error that carries the retry delay.

<CodeGroup>
  ```rust Rust theme={null}
  let gw = Tapedrive::new_gateway_read_only(rpc, GATEWAY_URL)?;
  let bytes = gw.read(&track).await?;

  // Into a sink instead of a buffer:
  let mut file = tokio::fs::File::create("photo.jpg").await?;
  gw.read_into(&manifest, &mut file).await?;
  ```
</CodeGroup>

## Direct URLs

Any track can be fetched over plain HTTP by its address, and the URL helper produces the link. Track-addressed URLs are stable and immutable, which makes them good for `img` tags, embeds, and [CDN origins](/tools/cdn). The endpoint itself is documented in the [gateway API](/apis/gateway/objects/get-object).

<CodeGroup>
  ```bash Gateway URL theme={null}
  curl "$TAPE_GATEWAY/object/<track-address>" -o photo.jpg
  ```
</CodeGroup>

## Range reads

Reads accept a byte range. For streamed objects, the range resolves the manifest and fetches only the segment tracks the range touches, so partial reads of large files stay cheap ([streams](/sdks/streams) explains the mechanics).

<CodeGroup>
  ```bash Gateway URL theme={null}
  # Standard HTTP Range against the object endpoint: 206 Partial Content
  curl -H "Range: bytes=0-1048575" "$TAPE_GATEWAY/object/<track-address>" -o first-mb.bin
  ```

  ```rust Rust theme={null}
  let gw = Tapedrive::new_gateway_read_only(rpc, gateway_url)?;
  let first_mb = gw.read_range(&track, 0, 1024 * 1024).await?;
  ```
</CodeGroup>

## Discovery and listings

Given only a wallet's pubkey, you can find its tape and list everything it stored: derive the tape address from the authority, then page through name-ordered listings. Each entry carries the name, size, content type, last-modified, and the underlying track address. Head a single object when you want metadata without the bytes.

<CodeGroup>
  ```rust Rust theme={null}
  let tape = client.get_tape(&tape_address).await?;
  let query = ListObjectsQuery::new("photos/").with_limit(100);
  let page = client.list_objects(&tape_address, query).await?;
  let meta = client.head_object(&tape_address, "photos/cat.jpg").await?;
  ```
</CodeGroup>

Below the object layer, chain-state track queries cover the rest: by address, by number, by lookup key, by tape, plus the proof query used for deletes and verification. They're listed on the [Rust page](/sdks/rust#the-modules).

## Verified reads

For readers who shouldn't trust the gateway. The trustless path fetches slices, verifies each against the on-chain commitment on your side, decodes, and verifies the decoded result before returning it.

A verified read costs more requests, and the compute core loads on demand. In exchange, the bytes you get are proven against the chain rather than taken on faith. Worth it for high-value reads, low-trust gateways, and spot-checks of your own data.

<CodeGroup>
  ```rust Rust theme={null}
  let bytes = gw.read(&track).await?;
  let ok = client.verify(&track, &bytes).await?;
  ```
</CodeGroup>

Two pieces do the work: the reader handles slice fetching and assembly (with a configurable slice source), and the verifier is the Merkle toolkit underneath.

## Error handling

Handle the cases the gateway actually returns, mapped to typed errors: not found, not yet certified, rate limited, and gateway-side retrieval failure. One timing case deserves code: a track certified moments ago may need a beat before every gateway serves it, and the polling helper covers that.

<CodeGroup>
  ```rust Rust theme={null}
  match reader.read_bytes(&track_id).await {
      Ok(bytes) => { /* ... */ }
      Err(TapedriveError::NotFound) => { /* unknown track */ }
      Err(TapedriveError::RateLimited { retry_after }) => { /* back off */ }
      Err(e) => return Err(e.into()),
  }
  // TODO(verify): exact TapedriveError variant names for not-found and rate-limited
  ```
</CodeGroup>

The gateway's own error conventions are on the [gateway API page](/apis/gateway).
