{"record":{"id":"4abf3666f115c977","repo":"p-e-w/heretic","slug":"prompts-must-not-be-empty","errorCode":null,"errorMessage":"prompts must not be empty","messagePattern":"prompts must not be empty","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/heretic/model.py","lineNumber":765,"sourceCode":"            residuals = torch.clamp(residuals, -thresholds, thresholds)\n\n        if self.settings.offload_outputs_to_cpu:\n            residuals = residuals.cpu()\n            empty_cache()\n\n        return residuals\n\n    def get_residuals_batched(self, prompts: list[Prompt]) -> Tensor:\n        residuals = []\n\n        for batch in batchify(prompts, self.settings.batch_size):\n            residuals.append(self.get_residuals(batch))\n\n        return torch.cat(residuals, dim=0)\n\n    def get_residuals_mean(self, prompts: list[Prompt]) -> Tensor:\n        if not prompts:\n            raise ValueError(\"prompts must not be empty\")\n\n        running_sum = None\n        total_count = 0\n\n        for batch in batchify(prompts, self.settings.batch_size):\n            batch_residuals = self.get_residuals(batch)\n\n            # Accumulate in high precision on CPU to reduce peak VRAM usage.\n            batch_sum = batch_residuals.sum(dim=0, dtype=torch.float64).cpu()\n\n            if running_sum is None:\n                running_sum = batch_sum\n            else:\n                running_sum += batch_sum\n\n            total_count += batch_residuals.shape[0]\n\n        assert running_sum is not None","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/p-e-w/heretic/blob/bedb94ef117a271532ac2058447fbc165d5051bd/src/heretic/model.py#L747-L783","documentation":"get_residuals_mean computes the mean of residual activations over a batch of prompts; with an empty list the mean is mathematically undefined (would return NaN or crash in torch.cat), so it validates up front and raises ValueError.","triggerScenarios":"Calling model.get_residuals_mean([]) — typically when the prompt dataset/filter produced no prompts, e.g. an empty sample set loaded from a file or all prompts filtered out upstream in run.","commonSituations":"An empty prompts JSON/JSONL file, a filter step that removed everything, or a dataset path pointing at the wrong (empty) file.","solutions":["Ensure the prompt list passed in is non-empty; check the source dataset/file","Add an early guard in your pipeline: if not prompts: raise or skip","Log the prompt-count before calling get_residuals_mean to catch empty inputs early"],"exampleFix":"// before\nmean = model.get_residuals_mean(prompts)\n// after\nif not prompts:\n    raise ValueError(\"No prompts loaded; check dataset file\")\nmean = model.get_residuals_mean(prompts)\n","handlingStrategy":"validation","validationCode":"if not prompts:\n    raise ValueError(\"prompts is empty; check dataset loading/filtering before calling get_residuals_mean\")","typeGuard":"def has_prompts(prompts: list) -> bool:\n    return isinstance(prompts, list) and len(prompts) > 0","tryCatchPattern":"try:\n    mean = model.get_residuals_mean(prompts)\nexcept ValueError:\n    logger.warning(\"No prompts to compute residuals over; skipping\")\n    mean = None","preventionTips":["Assert dataset non-empty right after loading prompts","Log prompt counts after each filter stage","Fail early in pipelines rather than at tensor computation"],"tags":["validation","empty-input","torch"],"backgroundTag":"empty-input-validation","analyzedSha":"bedb94ef117a271532ac2058447fbc165d5051bd","analyzedAt":"2026-08-29T08:38:06.692Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}