{"record":{"id":"99e88ac2f126306d","repo":"CorentinJ/Real-Time-Voice-Cloning","slug":"can-t-create-randomcycler-from-an-empty-collection","errorCode":null,"errorMessage":"Can't create RandomCycler from an empty collection","messagePattern":"Can't create RandomCycler from an empty collection","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"encoder/data_objects/random_cycler.py","lineNumber":14,"sourceCode":"import random\n\nclass RandomCycler:\n    \"\"\"\n    Creates an internal copy of a sequence and allows access to its items in a constrained random \n    order. For a source sequence of n items and one or several consecutive queries of a total \n    of m items, the following guarantees hold (one implies the other):\n        - Each item will be returned between m // n and ((m - 1) // n) + 1 times.\n        - Between two appearances of the same item, there may be at most 2 * (n - 1) other items.\n    \"\"\"\n    \n    def __init__(self, source):\n        if len(source) == 0:\n            raise Exception(\"Can't create RandomCycler from an empty collection\")\n        self.all_items = list(source)\n        self.next_items = []\n    \n    def sample(self, count: int):\n        shuffle = lambda l: random.sample(l, len(l))\n        \n        out = []\n        while count > 0:\n            if count >= len(self.all_items):\n                out.extend(shuffle(list(self.all_items)))\n                count -= len(self.all_items)\n                continue\n            n = min(count, len(self.next_items))\n            out.extend(self.next_items[:n])\n            count -= n\n            self.next_items = self.next_items[n:]\n            if len(self.next_items) == 0:\n                self.next_items = shuffle(list(self.all_items))","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/CorentinJ/Real-Time-Voice-Cloning/blob/890f3a03187195b9829db2079b75c2ba2ab0405c/encoder/data_objects/random_cycler.py#L1-L32","documentation":"Raised by RandomCycler.__init__ (encoder/data_objects/random_cycler.py) when the source sequence is empty. RandomCycler guarantees each item is returned between m//n and ((m-1)//n)+1 times; with n == 0 those guarantees are undefined and sample() would loop forever, so construction is rejected. The class is instantiated from exactly two places: SpeakerVerificationDataset (speaker_verification_dataset.py:18, with the list of speaker directories) and Speaker._load_utterances (speaker.py:18, with utterances parsed from the speaker's _sources.txt).","triggerScenarios":"The speaker.py path: a preprocessed speaker directory whose _sources.txt exists but is empty (encoder_preprocess.py wrote no utterances, e.g. all wav files failed VAD trimming), so `self.utterances` is [] and RandomCycler([]) raises during random_partial(). The dataset path requires zero speaker dirs, but that case is usually intercepted first by the 'No speakers found' exception in speaker_verification_dataset.py:15.","commonSituations":"Running encoder_train.py against a datasets_root where one speaker's audio was entirely too short/silent for preprocessing, leaving an empty _sources.txt; interrupted encoder_preprocess.py runs; a manually created speaker directory with no preprocessing output.","solutions":["Re-run preprocessing for the offending speaker: python encoder_preprocess.py -d <dataset> -i <datasets_root> (drop --skip_existing so empty outputs are regenerated).","Inspect each speaker dir: find <datasets_root>/SV2TTS/encoder -name _sources.txt -empty to locate the culprit, then delete or re-preprocess that directory.","If the speaker's source audio is genuinely unusable (all silence / <0.1s), remove that speaker directory before training.","As a library user, validate that a speaker dir has at least one *.npy frames file before constructing Speaker/RandomCycler."],"exampleFix":"# before (fails when _sources.txt is empty)\nspeaker = Speaker(speaker_dir)\nutterances, frames, ranges = speaker.random_partial(count, n_frames)\n\n# after (guard before use)\nspeaker = Speaker(speaker_dir)\nspeaker._load_utterances()\nassert speaker.utterances, f\"{speaker.name} has no preprocessed utterances\"\nutterances, frames, ranges = speaker.random_partial(count, n_frames)","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef valid_speaker_dir(speaker_dir: Path) -> bool:\n    src = speaker_dir / \"_sources.txt\"\n    if not src.is_file():\n        return False\n    return any(line.strip() for line in src.read_text().splitlines())","typeGuard":null,"tryCatchPattern":"try:\n    dataset = SpeakerVerificationDataset(root)\nexcept Exception as e:\n    if \"RandomCycler\" in str(e):\n        bad = [d for d in root.glob(\"*\") if d.is_dir() and not valid_speaker_dir(d)]\n        raise RuntimeError(f\"Empty speaker dirs: {bad}\") from e\n    raise","preventionTips":["After encoder_preprocess.py, run find <out>/SV2TTS/encoder -name _sources.txt -empty and reprocess or delete matches.","Treat interrupted preprocessing runs as suspect: re-run without --skip_existing.","Smoke-test one random_partial() call per speaker before launching a long training run."],"tags":["data","training","encoder","preprocessing"],"backgroundTag":null,"analyzedSha":"890f3a03187195b9829db2079b75c2ba2ab0405c","analyzedAt":"2026-08-15T02:15:13.202Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}