{"record":{"id":"6ad170758f25a45d","repo":"zylon-ai/private-gpt","slug":"invalid-request-error-6ad170","errorCode":"INVALID_REQUEST_ERROR","errorMessage":"Failed to upload file to S3 for async ingestion","messagePattern":"Failed to upload file to S3 for async ingestion","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"private_gpt/components/ingestion/ingestion_scheduler.py","lineNumber":451,"sourceCode":"        if ingest_body.ingest_body.input:\n            should_upload = (\n                not isinstance(ingest_body.ingest_body.input, UriArtifact)\n                or ingest_body.ingest_body.input.is_base64()\n            )\n            s3_helper = self._require_s3_helper()\n            if should_upload and s3_helper.is_available():\n                content = ingest_body.ingest_body.input.to_binary_content(\n                    get_file_name(ingest_body.ingest_body.metadata)\n                )\n                object_name = str(uuid.uuid4())\n                s3_url = s3_helper.upload_file_to_s3(\n                    filename=content.filename,\n                    bytes_data=content.data.read(),\n                    bucket_name=config.s3.temporary_bucket_name,\n                    object_name=object_name,\n                )\n                if not s3_url:\n                    raise ValueError(\"Failed to upload file to S3 for async ingestion\")\n                ingest_body.ingest_body.metadata = {\n                    **(ingest_body.ingest_body.metadata or {}),\n                    \"file_name\": content.filename,\n                }\n                ingest_body.ingest_body.input = UriArtifact(value=s3_url)\n\n        result = dispatch_task(\n            task_name=PARSE_TASK_NAME,\n            args=(ingest_body,),\n            queue=config.scheduler.ingestion.celery_queue,\n        )\n        task_id = result.task_id\n        if not isinstance(task_id, str):\n            raise ValueError(\"ingest_async did not return a valid task_id\")\n        return task_id\n\n    def ingest(self, ingest_body: IngestBody) -> IngestResponse:\n        \"\"\"Parse then store synchronously, blocking until both complete.\"\"\"","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/ingestion/ingestion_scheduler.py#L433-L469","documentation":"ValueError (mapped to INVALID_REQUEST_ERROR) raised in the async ingestion scheduler when upload_file_to_s3 returns a falsy URL after attempting to push binary ingest content to the configured temporary S3 bucket. The task is never dispatched to Celery — the request fails before scheduling.","triggerScenarios":"Submitting an async ingest request with should_upload true and s3_helper.is_available() true, but the S3 upload silently fails (helper returns None/empty instead of raising) — e.g. wrong credentials, unreachable endpoint, missing temporary_bucket_name bucket.","commonSituations":"Misconfigured S3 credentials or endpoint in config.s3; the temporary bucket does not exist or is in another region; MinIO not running in local dev; IAM policy without s3:PutObject.","solutions":["Verify config.s3 settings: endpoint URL, credentials, and temporary_bucket_name all correct and the bucket exists.","Test the helper directly: s3_helper.upload_file_to_s3(...) on a small file and inspect why it returns None (check its internal error swallowing).","Check IAM/MinIO policy grants s3:PutObject on the temporary bucket.","If S3 is not intended for this deployment, disable the should_upload path so content is passed inline."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if should_upload:\n    if not s3_helper.is_available():\n        raise RuntimeError('S3 helper reports unavailable')\n    if not config.s3.temporary_bucket_name:\n        raise RuntimeError('s3.temporary_bucket_name not configured')","typeGuard":null,"tryCatchPattern":"try:\n    task_id = scheduler.ingest_async(body)\nexcept ValueError as e:\n    if 'Failed to upload file to S3' in str(e):\n        return api_error(503, 'Storage backend temporarily unavailable; retry shortly')","preventionTips":["Add a startup connectivity check that PUTs a tiny object to temporary_bucket_name.","Alert when upload_file_to_s3 returns falsy — it swallows the underlying boto error; log it inside the helper."],"tags":["ingestion","s3","storage","configuration","async"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}