infiniflow/ragflow · error · PydanticCustomError
duplicate_uuids
duplicate_uuids
Error message
Duplicate ids: '{duplicate_ids}' What it means
PydanticCustomError (code duplicate_uuids) from DeleteReq.validate_ids (api/utils/validation_utils.py:869-940), the base class for DeleteDatasetReq/DeleteDocumentReq batch-delete payloads. After each entry passes UUID validation it is normalized to a 32-char lowercase hex via validate_uuid1_hex; the validator then counts occurrences with Counter and rejects the request if any normalized id appears more than once. Duplicates are reported back verbatim in the message so the caller sees exactly which ids collide.
Source
Thrown at api/utils/validation_utils.py:938
Security Notes:
- Validates UUID format (any version)
- Duplicate check prevents data injection
- None handling maintains pipeline integrity
"""
if v_list is None:
return None
ids_list = []
for v in v_list:
try:
ids_list.append(validate_uuid1_hex(v))
except PydanticCustomError as e:
raise e
duplicates = [item for item, count in Counter(ids_list).items() if count > 1]
if duplicates:
duplicates_str = ", ".join(duplicates)
raise PydanticCustomError("duplicate_uuids", "Duplicate ids: '{duplicate_ids}'", {"duplicate_ids": duplicates_str})
return ids_list
class DeleteDatasetReq(DeleteReq):
"""Request model for deleting datasets."""
...
class DeleteDocumentReq(DeleteReq):
"""Request model for deleting documents."""
@field_validator("ids", mode="after")
@classmethod
def validate_ids(cls, v_list: list[str] | None) -> list[str] | None:
"""
Validate document IDs without enforcing UUIDv1.View on GitHub (pinned to 554fb1133a)
Solutions
- Deduplicate the ids array client-side before sending (use set() or dict.fromkeys to preserve order).
- Normalize ids to lowercase 32-char hex before comparing so case/hyphen variants collapse.
- Inspect the '{duplicate_ids}' value in the error message to find which entry was repeated.
Example fix
# before
payload = {"ids": selected_ids} # may contain repeats
# after
payload = {"ids": list(dict.fromkeys(selected_ids))} Defensive patterns
Strategy: validation
Validate before calling
import uuid
normalized = [uuid.UUID(x).hex for x in ids]
if len(set(normalized)) != len(normalized):
raise ValueError("duplicate dataset/document ids after normalization") Type guard
def has_unique_uuid_ids(ids: list[str] | None) -> bool:
if ids is None:
return True
seen = set()
for x in ids:
h = uuid.UUID(x).hex
if h in seen:
return False
seen.add(h)
return True Try / catch
try:
req = DeleteDatasetReq(ids=ids)
except ValidationError as e:
if any(err["type"] == "duplicate_uuids" for err in e.errors()):
ids = list(dict.fromkeys(ids)) # dedup and retry once
req = DeleteDatasetReq(ids=ids)
else:
raise Prevention
- Normalize UUIDs to lowercase hex before comparing/deduplicating.
- Deduplicate with dict.fromkeys to preserve order.
- When merging id lists from multiple sources, dedup as the final build step.
When it happens
Trigger: DELETE /api/v1/datasets or /api/v1/documents with an ids array containing the same UUID twice — including cases where the two strings differ only in case or hyphenation (e.g. 'ABC...' vs 'abc...', hyphenated vs bare hex) because normalization happens before the duplicate check.
Common situations: Front-end accumulating selection across pages and adding the same row twice; scripts concatenating id lists without dedup; mixed-format UUIDs (upper/lower case, with/without dashes) coming from different sources that normalize to the same id.
Related errors
- invalid_uuid_format
- format_invalid
- At least one of dest_file_id or new_name must be provided
- new_name can only be used with a single file
- main() must be defined or exported.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/a77e566d63a80d7f.
Report an issue: GitHub.