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.
Summary
On the
collection.data.ingest()(server-side batching) path,BatchObjectReturn.has_errorsstaysFalseeven whenBatchObjectReturn.errorsis populated.collection.batch.failed_objectsis 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:The practical consequence is that the idiomatic error check silently never fires:
if result.has_errors:is alwaysFalseafteringest(), so failed objects are dropped without the caller noticing.Reproduction
Actual
result.errorsitself is correct and well formed, keyed by the original index:Expected
...and
collection.batch.failed_objectspopulated, matching thebatch.stream()behavior.Contrast:
batch.stream()worksRunning the same two objects through the streaming path on an identical collection:
So the error information reaches the client on both paths; only the
ingest()path fails to sethas_errorsand fails to surfacefailed_objects.Notably, the server-side error message itself advises
use {client,collection}.batch.failed_objects to access this error, which is not reachable on theingest()path.Environment
weaviate-client4.22.0cr.weaviate.io/semitechnologies/weaviate:1.38.0, anonymous access, self-provided vectors)uv run --with 'weaviate-client==4.22.0'Notes
has_errorsis assigned inweaviate/collections/classes/batch.pyat:233(merge) and:262, so the flag is set on some paths; theingest()/ server-side batching path appears not to reach either.This also affects documentation: the Weaviate docs examples for
data.ingest()currently have to gate onif result.errors:rather than the more naturalif result.has_errors:, because the latter never fires.