{"record":{"id":"d7e23d432fb21f17","repo":"hacksider/Deep-Live-Cam","slug":"max-k-must-be-at-least-1","errorCode":null,"errorMessage":"max_k must be at least 1","messagePattern":"max_k must be at least 1","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"modules/cluster_analysis.py","lineNumber":11,"sourceCode":"import numpy as np\nfrom sklearn.cluster import KMeans\nfrom typing import Any\n\n\ndef find_cluster_centroids(embeddings, max_k=10) -> Any:\n    n_samples = len(embeddings)\n    if n_samples == 0:\n        raise ValueError(\"embeddings must not be empty\")\n    if max_k < 1:\n        raise ValueError(\"max_k must be at least 1\")\n\n    max_k = min(max_k, n_samples)\n    if max_k == 1:\n        kmeans = KMeans(n_clusters=1, random_state=0)\n        kmeans.fit(embeddings)\n        return kmeans.cluster_centers_\n\n    inertia = []\n    cluster_centroids = []\n    K = range(1, max_k+1)\n\n    for k in K:\n        kmeans = KMeans(n_clusters=k, random_state=0)\n        kmeans.fit(embeddings)\n        inertia.append(kmeans.inertia_)\n        cluster_centroids.append({\"k\": k, \"centroids\": kmeans.cluster_centers_})\n\n    diffs = [inertia[i] - inertia[i+1] for i in range(len(inertia)-1)]","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/hacksider/Deep-Live-Cam/blob/987f6b392b1740623b3fa8a5cb46fdd0b7e185b9/modules/cluster_analysis.py#L1-L29","documentation":"ValueError raised by find_cluster_centroids in modules/cluster_analysis.py when the max_k argument is less than 1. max_k caps how many candidate cluster counts (K = 1..max_k) the elbow search evaluates, so 0 or negative values make the search range empty and meaningless. The function validates this up front and fails fast.","triggerScenarios":"Calling find_cluster_centroids(embeddings, max_k=0) or with a negative max_k. Most often max_k is computed from data or config (e.g. max_k = n // 10, or a CLI/config value) and the computation yields 0 for a small n or a misconfigured setting.","commonSituations":"max_k derived as a fraction of sample count with small inputs (n=5, max_k=n//10 -> 0); a config file or CLI flag with an unset/zero k value; unit tests parameterized with edge-case k values; off-by-one when converting an inclusive/exclusive upper bound.","solutions":["Pass an explicit max_k >= 1 (the default of 10 is safe; it is internally clamped via min(max_k, n_samples)).","If max_k is computed, clamp it: max_k = max(1, min(max_k, n_samples)) before the call.","Fix the config/CLI source that produced 0 or a negative value."],"exampleFix":"# before\nmax_k = len(embeddings) // 10\ncentroids = find_cluster_centroids(embeddings, max_k)\n\n# after\nmax_k = max(1, len(embeddings) // 10)\ncentroids = find_cluster_centroids(embeddings, max_k)","handlingStrategy":"validation","validationCode":"max_k = max(1, min(max_k, len(embeddings))) if embeddings else 1\ncentroids = find_cluster_centroids(embeddings, max_k=max_k)","typeGuard":null,"tryCatchPattern":"try:\n    centroids = find_cluster_centroids(embeddings, max_k=k)\nexcept ValueError as e:\n    if \"max_k must be at least 1\" in str(e):\n        k = max(1, k)\n        centroids = find_cluster_centroids(embeddings, max_k=k)\n    else:\n        raise","preventionTips":["Never derive max_k with unclamped integer math (n // divisor can hit 0).","Validate config-supplied k values against 1 <= k <= n_samples at load time.","Remember the function already clamps max_k to n_samples, so only the >= 1 floor is your job."],"tags":["python","sklearn","clustering","validation","off-by-one"],"backgroundTag":null,"analyzedSha":"987f6b392b1740623b3fa8a5cb46fdd0b7e185b9","analyzedAt":"2026-08-14T19:48:25.860Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}