{"record":{"id":"b84f53bcee552f18","repo":"JuliusBrussee/caveman","slug":"invalid-scope-b84f53","errorCode":"invalid_scope","errorMessage":"invalid_scope","messagePattern":"invalid_scope","errorType":"error_code","errorClass":"MiddlewareError","httpStatus":null,"severity":"error","filePath":"packages/sdk/python/caveman_cloud/middleware/validate.py","lineNumber":30,"sourceCode":"    return hashlib.sha256(text.encode(\"utf-8\")).hexdigest()\n\n\ndef token(value: Any) -> bool:\n    return isinstance(value, str) and re.fullmatch(r\"[a-zA-Z0-9._:/-]{1,256}\", value) is not None\n\n\ndef digest(value: Any) -> bool:\n    return isinstance(value, str) and re.fullmatch(r\"[a-f0-9]{64}\", value) is not None\n\n\ndef integer(value: Any) -> bool:\n    return type(value) is int and 0 <= value <= 9007199254740991\n\n\ndef scope_key(scope: Scope) -> str:\n    values = list(asdict(scope).values())\n    if not all(token(v) for v in values):\n        raise MiddlewareError(\"invalid_scope\")\n    return json.dumps(values, separators=(\",\", \":\"))\n\n\ndef capabilities(value: Any) -> dict[str, Any]:\n    try:\n        if (type(value[\"schema_version\"]) is not int or value[\"schema_version\"] != 1 or not token(value[\"policy_revision\"])\n                or not isinstance(value[\"runtime_build\"], str) or value[\"mode\"] not in (\"record\", \"compress\")\n                or not isinstance(value[\"transforms\"], list) or len(value[\"transforms\"]) > 128\n                or not all(integer(value[\"limits\"][k]) and value[\"limits\"][k] > 0 for k in (\"deadline_ms\", \"request_bytes\", \"segment_bytes\", \"page_bytes\"))\n                or not integer(value[\"retention_seconds\"]) or type(value[\"recovery\"]) is not bool\n                or type(value[\"persistent\"]) is not bool):\n            raise ValueError()\n        seen = set()\n        for t in value[\"transforms\"]:\n            if (not token(t[\"transform_id\"]) or t[\"transform_id\"] in seen or not token(t[\"implementation_version\"])\n                    or not isinstance(t[\"eligible_segment_kinds\"], list) or t[\"recovery\"] not in (\"exact_ccr\", \"none\") or t[\"deterministic\"] is not True):\n                raise MiddlewareError(\"unknown_capability\")\n            seen.add(t[\"transform_id\"])","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/sdk/python/caveman_cloud/middleware/validate.py#L12-L48","documentation":"MiddlewareError raised by scope_key() when any field of a Scope dataclass fails the token() check (must be an int in [0, 9007199254740991] or a valid token string). The scope is serialized to a JSON key for caching/dedup, so every value must be a safe primitive; anything else (floats, bools, None, oversized ints, bad strings) is rejected before it can corrupt cache keys.","triggerScenarios":"Calling any public API that takes a Scope (optimize and friends) with a scope containing None, a float, a bool-typed int confusion, an int > 2^53-1, or a negative int in one of its fields — typically a hand-constructed Scope rather than one produced by the library.","commonSituations":"Constructing Scope manually from parsed config where a field is None or a string number; JavaScript interop writing numbers that exceed 2^53-1; a config file supplying \"source_id\": null.","solutions":["Validate/fill every Scope field before calling: ensure ints are in 0..9007199254740991 and strings pass the token charset","Build scopes via the SDK's own constructors/helpers instead of hand-assembling the dataclass","Fix the config source that produced None/oversized values and re-run","Pre-check with the snippet below before making the call"],"exampleFix":"# before\nscope = Scope(source_id=None, revision=2**60)  # invalid_scope\n# after\nif not (0 <= revision <= 9007199254740991) or source_id is None:\n    raise ValueError(\"bad scope fields\")\nscope = Scope(source_id=source_id, revision=revision)","handlingStrategy":"validation","validationCode":"def scope_is_valid(scope) -> bool:\n    from dataclasses import asdict\n    def tok(v):\n        return (type(v) is int and 0 <= v <= 9007199254740991) or (isinstance(v, str) and v.isprintable() and v)\n    return all(tok(v) for v in asdict(scope).values())\n# call scope_is_valid(scope) before any API that takes the scope","typeGuard":"def valid_scope_value(v) -> bool:\n    return type(v) is int and 0 <= v <= 9007199254740991 or isinstance(v, str) and len(v) > 0","tryCatchPattern":"try:\n    result = client.optimize(request, scope=scope)\nexcept MiddlewareError as e:\n    if e.args[0] == \"invalid_scope\":\n        log.error(\"scope fields must be ints in [0, 2^53-1] or valid tokens\")\n    raise","preventionTips":["Always build scopes through SDK helpers, never hand-assemble the dataclass","Validate config-derived scope fields (no None, no floats, no ints > 2^53-1) at load time","Remember the 2^53-1 limit when interoping with JavaScript numbers","Unit-test scope construction from every config source"],"tags":["validation","scope","python"],"backgroundTag":"invalid-argument-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}