Skip to content

data.ingest(): BatchObjectReturn.has_errors stays False when errors is populated (and batch.failed_objects is empty) #2107

Description

@g-despot

Summary

On the collection.data.ingest() (server-side batching) path, BatchObjectReturn.has_errors stays False even when BatchObjectReturn.errors is populated. collection.batch.failed_objects is also empty on that path.

The equivalent collection.batch.stream() path behaves correctly on the same input.

This contradicts the documented contract in weaviate/collections/classes/batch.py:210:

has_errors: A boolean indicating whether or not any of the objects in the batch failed to be inserted. If this is True, then the errors dictionary will contain at least one entry.

The practical consequence is that the idiomatic error check silently never fires: if result.has_errors: is always False after ingest(), so failed objects are dropped without the caller noticing.

Reproduction

import weaviate
import weaviate.classes.config as wc

with weaviate.connect_to_local() as client:
    client.collections.delete("ReproColl")
    coll = client.collections.create(
        name="ReproColl",
        properties=[
            wc.Property(name="title", data_type=wc.DataType.TEXT),
            wc.Property(name="count", data_type=wc.DataType.INT),
        ],
        vector_config=wc.Configure.Vectors.self_provided(),
    )

    objs = [
        {"title": "ok", "count": 1},
        {"title": "bad", "count": "not-an-int"},   # violates the INT property type
    ]

    result = coll.data.ingest(objs)

    print("len(result.errors)   :", len(result.errors))
    print("result.has_errors    :", result.has_errors)
    print("len(failed_objects)  :", len(coll.batch.failed_objects))

Actual

len(result.errors)   : 1
result.has_errors    : False
len(failed_objects)  : 0

result.errors itself is correct and well formed, keyed by the original index:

{1: ErrorObject(message="invalid integer property 'count' on class 'ReproColl': requires an integer, the given value is 'not-an-int'",
                object_=BatchObject(collection='ReproColl', properties={'title': 'bad', 'count': 'not-an-int'}, ..., index=1, retry_count=0),
                original_uuid=None)}

Expected

len(result.errors)   : 1
result.has_errors    : True

...and collection.batch.failed_objects populated, matching the batch.stream() behavior.

Contrast: batch.stream() works

Running the same two objects through the streaming path on an identical collection:

with coll2.batch.stream() as batch:
    for o in objs:
        batch.add_object(properties=o)

print(len(coll2.batch.failed_objects))   # -> 1
batch.failed_objects  : 1 entry/entries
  - invalid integer property 'count' on class 'ReproColl2': requires an integer, the given value is 'not-an-int'

So the error information reaches the client on both paths; only the ingest() path fails to set has_errors and fails to surface failed_objects.

Notably, the server-side error message itself advises use {client,collection}.batch.failed_objects to access this error, which is not reachable on the ingest() path.

Environment

  • weaviate-client 4.22.0
  • Weaviate server 1.38.0 (cr.weaviate.io/semitechnologies/weaviate:1.38.0, anonymous access, self-provided vectors)
  • Reproduced on macOS, Python via uv run --with 'weaviate-client==4.22.0'

Notes

has_errors is assigned in weaviate/collections/classes/batch.py at :233 (merge) and :262, so the flag is set on some paths; the ingest() / server-side batching path appears not to reach either.

This also affects documentation: the Weaviate docs examples for data.ingest() currently have to gate on if result.errors: rather than the more natural if result.has_errors:, because the latter never fires.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions