{"record":{"id":"85200f3b4d12dd17","repo":"calesthio/OpenMontage","slug":"duration-must-be-an-integer-from-4-to-max-seconds","errorCode":null,"errorMessage":"duration must be an integer from 4 to {max_seconds} or -1","messagePattern":"duration must be an integer from 4 to (.+?) or -1","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/video/seedance_ark.py","lineNumber":933,"sourceCode":"            or os.environ.get(\"ARK_SEEDANCE_MODEL\")\n            or self.MODEL_IDS[variant]\n        )\n        if not model or any(char.isspace() for char in model):\n            raise ValueError(\"model must be a non-empty Ark Model/Endpoint ID\")\n        for known_variant, known_model in self.MODEL_IDS.items():\n            if model == known_model:\n                return model, known_variant\n        # Endpoint IDs and future model IDs can have account-specific pricing.\n        # Keep the caller's requested model, but never pretend its price is the\n        # public price of model_variant.\n        return model, None\n\n    @staticmethod\n    def _normalize_duration(value: Any, max_seconds: int = 15) -> int:\n        if value == \"auto\":\n            return -1\n        if isinstance(value, bool):\n            raise ValueError(\n                f\"duration must be an integer from 4 to {max_seconds} or -1\"\n            )\n        try:\n            duration = int(value)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(\n                f\"duration must be an integer from 4 to {max_seconds} or -1\"\n            ) from exc\n        if str(value).strip() not in {str(duration), \"auto\"}:\n            raise ValueError(\n                f\"duration must be an integer from 4 to {max_seconds} or -1\"\n            )\n        if duration != -1 and not 4 <= duration <= max_seconds:\n            raise ValueError(f\"duration must be between 4 and {max_seconds} or -1\")\n        return duration\n\n    @staticmethod\n    def _single_image_refs(inputs: dict[str, Any]) -> list[Any]:","sourceCodeStart":915,"sourceCodeEnd":951,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/seedance_ark.py#L915-L951","documentation":"Raised by _normalize_duration when the duration value cannot be accepted as an integer in [4, max_seconds] or the -1 'auto' marker. Beyond non-integers, it deliberately rejects values like '5s', ' 5 ', and 5.5 whose string form does not round-trip to the parsed integer — a strictness guard against silent coercion. max_seconds defaults to 15 (the code path that formats the message).","triggerScenarios":"duration='5s', duration=5.5, duration=' 5', duration=True (bools rejected before int coercion), or a non-numeric string; 'auto' and -1 are accepted, and '5' / 5 pass.","commonSituations":"Forwarding UI strings like '10s'; passing a float computed from a seconds calculation; boolean flags leaking into duration from config merges; unit confusion (frames vs seconds).","solutions":["Pass duration as a plain integer 4..15 (or -1 / 'auto')","Strip unit suffixes and round before calling: duration=int(str(value).strip().rstrip('s'))","Validate durations at the config/UI boundary so '5s'-style strings never reach the tool"],"exampleFix":"# before\ninputs = {\"duration\": \"10s\"}\n\n# after\ninputs = {\"duration\": 10}","handlingStrategy":"validation","validationCode":"def normalize_duration(value, max_seconds=15):\n    if value in (-1, \"auto\", \"-1\"):\n        return -1\n    if isinstance(value, bool):\n        raise ValueError(\"duration must be an int 4..%d or -1\" % max_seconds)\n    try:\n        d = int(str(value).strip().rstrip(\"s\").strip())\n    except ValueError:\n        raise ValueError(\"duration must be an int 4..%d or -1\" % max_seconds)\n    if not (4 <= d <= max_seconds or d == -1):\n        raise ValueError(\"duration must be an int 4..%d or -1\" % max_seconds)\n    return d\n\ninputs[\"duration\"] = normalize_duration(inputs.get(\"duration\"))","typeGuard":"def is_valid_duration(value, max_seconds=15) -> bool:\n    if value in (-1, \"auto\"): return True\n    if isinstance(value, bool): return False\n    try:\n        d = int(value)\n    except (TypeError, ValueError):\n        return False\n    return str(value).strip() in {str(d), \"auto\"} and (4 <= d <= max_seconds or d == -1)","tryCatchPattern":null,"preventionTips":["Send integers only; strip 's' suffixes at the UI boundary","Reject float durations at config validation, not deep in the pipeline"],"tags":["validation","seedance","ark","duration","type-coercion","input-validation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}