docling-project/docling · error · ValueError

submit_batch() received both 'target' and 'targets'; supply

Error message

submit_batch() received both 'target' and 'targets'; supply only one.

What it means

submit_batch() on the async service client accepts either 'target' (single target) or keyword-only 'targets' (list), never both. Supplying both is ambiguous — the API payload would need to choose one 'target'/'targets' field — so the client raises ValueError before building the BatchConvertSourcesRequest. This is a caller-side API misuse error, not a server error.

Source

Thrown at docling/service_client/_async_client.py:316

    async def submit_batch(
        self,
        sources: Sequence[BatchSourceRequestInput],
        target: BatchTargetRequestInput | None = None,
        output_formats: list[OutputFormat] | None = None,
        options: ConvertDocumentsRequestOptions | None = None,
        headers: dict[str, str] | None = None,
        *,
        targets: list[BatchTargetRequestInput] | None = None,
    ) -> (
        AsyncConversionJob[PresignedUrlConvertDocumentResponse]
        | AsyncConversionJob[PresignedUrlConvertResponse]
    ):
        assert self._async_client is not None, "client not open — use async with"
        if target is None and targets is None:
            raise ValueError("submit_batch() requires either 'target' or 'targets'.")
        if target is not None and targets is not None:
            raise ValueError(
                "submit_batch() received both 'target' and 'targets'; supply only one."
            )
        payload: dict[str, Any] = {"sources": sources}
        if targets is not None:
            payload["targets"] = targets
        else:
            payload["target"] = target
        request = BatchConvertSourcesRequest.model_validate(payload)
        resolved = self._resolve_options(
            options=options,
            max_num_pages=None,
            max_file_size=None,
            page_range=None,
        )
        # Use the first effective target for output-format hint.
        first_target = (request.targets or [request.target])[0]
        submit_options = self._options_for_output_formats(
            resolved.options,

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Keep exactly one of the two: drop target= when migrating to targets=[...], or vice versa.
  2. If wrapping submit_batch, decide which form your wrapper exposes and forward only that parameter.
  3. Add a unit assertion in wrappers that never both are set.

Example fix

# before
job = await client.submit_batch(sources=s, target=t, targets=[t, t2])

# after
job = await client.submit_batch(sources=s, targets=[t, t2])
Defensive patterns

Strategy: validation

Validate before calling

assert not (target is not None and targets is not None), 'pass only one of target/targets'

Prevention

When it happens

Trigger: Calling submit_batch(sources=..., target=..., targets=[...]) with both populated; refactoring code from single-target to multi-target and leaving the old target= argument in place; framework code that forwards **kwargs containing target while also passing targets explicitly.

Common situations: Migrating an existing submit_batch call to the plural API without removing the old argument; generic wrapper functions that pass all options through; IDE autocompletion adding both parameters.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/ececc10acda3bd98. Report an issue: GitHub.