{"record":{"id":"703f54d8df9bf9b0","repo":"chroma-core/chroma","slug":"limit-must-be-a-non-negative-integer-703f54","errorCode":null,"errorMessage":"limit must be a non-negative integer","messagePattern":"limit must be a non-negative integer","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/api/segment.py","lineNumber":807,"sourceCode":"            tenant=tenant,\n            ids=ids,\n            where=where,\n            where_document=where_document,\n        )\n\n        self._manager.hint_use_collection(collection_id, t.Operation.DELETE)\n\n        if (where or where_document) or not ids:\n            ids_to_delete = self._executor.get(\n                GetPlan(scan, Filter(ids, where, where_document))\n            )[\"ids\"]\n        else:\n            ids_to_delete = ids\n\n        # Apply limit if specified (validated upstream, but enforce defensively)\n        if limit is not None:\n            if not isinstance(limit, int) or isinstance(limit, bool) or limit < 0:\n                raise ValueError(\"limit must be a non-negative integer\")\n            if where is None and where_document is None:\n                raise ValueError(\n                    \"limit can only be specified when a where or where_document clause is provided\"\n                )\n            ids_to_delete = ids_to_delete[:limit]\n\n        if len(ids_to_delete) == 0:\n            return DeleteResult(deleted=0)\n\n        records_to_submit = list(\n            _records(operation=t.Operation.DELETE, ids=ids_to_delete)\n        )\n        self._validate_embedding_record_set(scan.collection, records_to_submit)\n        self._producer.submit_embeddings(collection_id, records_to_submit)\n\n        deleted_count = len(ids_to_delete)\n\n        self._product_telemetry_client.capture(","sourceCodeStart":789,"sourceCodeEnd":825,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/api/segment.py#L789-L825","documentation":"collection.delete(..., limit=n) caps how many matched records are deleted. SegmentAPI re-validates limit defensively ('validated upstream, but enforce defensively'): it must be a real int (bool is explicitly rejected, since isinstance(True, int) is True in Python) and non-negative. Violations raise ValueError('limit must be a non-negative integer').","triggerScenarios":"coll.delete(where=..., limit=-1), limit=2.5, limit='10' (string from JSON/query params), or limit=True — any bool, non-int, or negative value passed as limit.","commonSituations":"Forwarding untyped user input (HTTP query params, config files) straight into limit; using -1 as an 'unlimited' sentinel carried over from SQL habits; JSON configs where numbers deserialize as strings.","solutions":["Normalize before the call: cast to int, reject bools, require >= 0 — or pass None to skip limiting","Use None instead of -1/0-style sentinels when you mean 'no limit'","Validate kwargs once in a wrapper so every delete path gets a clean limit"],"exampleFix":"// before\nn = request.args.get('limit', -1)  # arrives as '-1' or -1\ncoll.delete(where=f, limit=n)\n\n// after\nraw = request.args.get('limit')\nn = int(raw) if raw is not None else None\nassert n is None or (isinstance(n, int) and not isinstance(n, bool) and n >= 0)\ncoll.delete(where=f, limit=n)","handlingStrategy":"validation","validationCode":"def normalize_delete_limit(value):\n    if value is None:\n        return None\n    if isinstance(value, bool) or not isinstance(value, int) or value < 0:\n        raise ValueError(f'limit must be a non-negative int, got {value!r}')\n    return value\n\ncoll.delete(where=f, limit=normalize_delete_limit(raw_limit))","typeGuard":"def is_valid_delete_limit(v) -> bool:\n    return v is None or (isinstance(v, int) and not isinstance(v, bool) and v >= 0)","tryCatchPattern":null,"preventionTips":["Cast and bound user-supplied limits at the API boundary (int(...) with try/except)","Remember bool is a subclass of int in Python — reject it explicitly","Use None for 'no limit', never -1"],"tags":["chroma","delete","limit","parameter-validation","type-coercion"],"backgroundTag":"invalid-parameter-value","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}