{"record":{"id":"a4cc10c5f3b063df","repo":"rohitg00/ai-engineering-from-scratch","slug":"reusable-file-id-must-not-be-empty","errorCode":null,"errorMessage":"reusable_file_id must not be empty","messagePattern":"reusable_file_id must not be empty","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"certifications/claude/lessons/08-messages-api-and-application-lifecycle/code/main.py","lineNumber":200,"sourceCode":"\n\ndef stable_cache_key(model: str, stable_prefix: str) -> str:\n    payload = f\"{model}\\0{stable_prefix}\".encode(\"utf-8\")\n    return hashlib.sha256(payload).hexdigest()\n\n\nIMAGE_MEDIA_TYPES = {\"image/jpeg\", \"image/png\", \"image/gif\", \"image/webp\"}\nDOCUMENT_MEDIA_TYPES = {\"application/pdf\", \"text/plain\"}\n\n\ndef build_multimodal_request(prompt: str, image_bytes: bytes, reusable_file_id: str) -> dict[str, Any]:\n    \"\"\"Build an offline request body with inline vision and a reusable file asset.\"\"\"\n    if not prompt.strip():\n        raise ValueError(\"prompt must not be empty\")\n    if not image_bytes:\n        raise ValueError(\"image_bytes must not be empty\")\n    if not reusable_file_id.strip():\n        raise ValueError(\"reusable_file_id must not be empty\")\n    return {\n        \"model\": \"<current-model-id>\",\n        \"max_tokens\": 400,\n        \"messages\": [\n            {\n                \"role\": \"user\",\n                \"content\": [\n                    {\"type\": \"text\", \"text\": prompt},\n                    {\n                        \"type\": \"image\",\n                        \"source\": {\n                            \"type\": \"base64\",\n                            \"media_type\": \"image/png\",\n                            \"data\": base64.b64encode(image_bytes).decode(\"ascii\"),\n                        },\n                    },\n                    {\n                        \"type\": \"document\",","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/certifications/claude/lessons/08-messages-api-and-application-lifecycle/code/main.py#L182-L218","documentation":"Raised by build_multimodal_request when reusable_file_id is empty or whitespace-only. The builder attaches a reusable file asset by id; an empty id cannot reference anything and would silently drop the document context from the request (multimodal_lab_fixture).","triggerScenarios":"Calling build_multimodal_request('prompt', image_bytes, '') or '   ' when an upload step failed and its id variable was never set.","commonSituations":"A file-upload call failed silently and left the id unset, string formatting of the id produced an empty value, or fixture placeholders not filled in.","solutions":["Pass the id returned by a successful file upload","Check the upload response for the id field before building the request","Default ids to a sentinel in fixtures and assert they were replaced"],"exampleFix":"# before\nfile_id = \"\"\nif upload_ok:\n    file_id = resp[\"id\"]\nbuild_multimodal_request(prompt, img, file_id)\n# after\nif not upload_ok:\n    raise ValueError(\"upload failed\")\nbuild_multimodal_request(prompt, img, resp[\"id\"])","handlingStrategy":"validation","validationCode":"if not reusable_file_id or not reusable_file_id.strip():\n    raise ValueError(\"file upload did not return an id\")\nreq = build_multimodal_request(prompt, image_bytes, reusable_file_id)","typeGuard":"def is_file_id(value: object) -> bool:\n    return isinstance(value, str) and bool(value.strip())","tryCatchPattern":null,"preventionTips":["Extract the id from the upload response immediately and fail if absent","Never build requests on failure paths where the upload was skipped"],"tags":["file-upload","multimodal","argument-validation","python"],"backgroundTag":"missing-file-id","analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}