tikv/tikv · error · sst_importer::Error

download method only accepts single-file requests, use batch

Error message

download method only accepts single-file requests, use batch_download for multi-file requests

What it means

The legacy single-file download gRPC method rejects requests that carry a multi-file ssts set. The batch API (batch_download) exists for multi-file requests, so the single-file method guards against misuse and returns the error inside the DownloadResponse instead of failing the RPC.

Source

Thrown at src/import/sst_service.rs:1085

        };
        self.threads.spawn(handle_task);
    }

    /// Downloads the file and performs key-rewrite for later ingesting.
    fn download(
        &mut self,
        _ctx: RpcContext<'_>,
        req: DownloadRequest,
        sink: UnarySink<DownloadResponse>,
    ) {
        let label = "download";
        IMPORT_RPC_COUNT.with_label_values(&[label]).inc();
        let timer = Instant::now_coarse();

        // download method only handles single file downloads
        // Check that this is indeed a single-file request
        if !req.get_ssts().is_empty() {
            let error = sst_importer::Error::Io(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "download method only accepts single-file requests, use batch_download for multi-file requests",
            ));
            let mut resp = DownloadResponse::default();
            resp.set_error(error.into());
            let _ = sink
                .success(resp)
                .map_err(|e| warn!("send rpc response"; "err" => %e));
            return;
        }
        let importer = Arc::clone(&self.importer);
        let download_speed_limiter = self.download_speed_limiter.clone();
        let mem_limit = self.mem_limit;
        let tablets = self.tablets.clone();
        let start = Instant::now();
        let resource_limiter = self.resource_manager.as_ref().and_then(|r| {
            r.get_background_resource_limiter(
                req.get_context()

View on GitHub (pinned to 78aedc1c81)

Solutions

  1. Populate req.ssts and call batch_download instead
  2. For a single file, use the single-file fields of the DownloadRequest with the download method
  3. Fix client code that sets ssts unconditionally regardless of method

Example fix

// before
req.set_ssts(vec![meta]);
client.download(req).await?;
// after: single-file request uses the single-file field
req.mut_sst().clone_from(&meta);
client.download(req).await?;
// or, for multiple files:
// client.batch_download(req_with_ssts).await?;
Defensive patterns

Strategy: validation

Validate before calling

if !req.get_ssts().is_empty() {
    return Err("use batch_download for multi-file requests");
}

Try / catch

let resp = client.download(req).await?;
if let Some(err) = resp.get_error() {
    if err.get_message().contains("single-file") {
        return client.batch_download(req_for_batch).await.map_err(Into::into);
    }
    return Err(err.clone().into());
}

Prevention

When it happens

Trigger: Invoking the download RPC with req.ssts non-empty (i.e. a DownloadRequest built for the batch API).

Common situations: BR/tooling code migrated to the batch API but still pointing at the download method; codegen or hand-written clients filling both the legacy single-file fields and ssts.

Related errors


AI-assisted analysis of tikv/tikv@78aedc1c81 (2026-09-03). Data as JSON: /api/errors/9e64b452f89deffb. Report an issue: GitHub.