{"record":{"id":"e9b6ae18539dab55","repo":"ComposioHQ/composio","slug":"file-upload-was-aborted-because-before-file-upload","errorCode":null,"errorMessage":"File upload was aborted because before_file_upload returned False.","messagePattern":"File upload was aborted because before_file_upload returned False\\.","errorType":"exception","errorClass":"FileUploadAbortedError","httpStatus":null,"severity":"warning","filePath":"python/composio/core/models/_files.py","lineNumber":610,"sourceCode":"        :return: FileUploadable instance with S3 key\n        \"\"\"\n        file_str = str(file) if isinstance(file, Path) else file\n        path_in = file_str\n        source: t.Literal[\"url\", \"path\"] = (\n            \"url\" if isinstance(file_str, str) and _is_url(file_str) else \"path\"\n        )\n\n        if before_file_upload is not None:\n            out = before_file_upload(\n                {\n                    \"path\": path_in,\n                    \"source\": source,\n                    \"tool\": tool,\n                    \"toolkit\": toolkit,\n                }\n            )\n            if out is False:\n                raise FileUploadAbortedError(\n                    \"File upload was aborted because before_file_upload returned False.\"\n                )\n            if isinstance(out, str):\n                path_in = out\n\n        # Re-decide routing on the post-hook value: a URL-source hook may return\n        # a local path (and vice versa). Re-checking with `_is_url` keeps the\n        # URL fetch path and the local-file path properly separated, so a hook\n        # cannot, for example, smuggle `/etc/passwd` past the URL branch's\n        # missing allowlist/denylist by rewriting the URL into a path.\n        if isinstance(path_in, str) and _is_url(path_in):\n            return cls.from_url(client=client, url=path_in, tool=tool, toolkit=toolkit)\n\n        # Allowlist check runs BEFORE the denylist / existence checks when enabled,\n        # so the \"configure file_upload_dirs\" hint fires first for the common case\n        # (user has auto-upload on but hasn't configured dirs). Caller passes\n        # ``None`` to bypass the allowlist (manual upload APIs).\n        if file_upload_allowlist is not None:","sourceCodeStart":592,"sourceCodeEnd":628,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/_files.py#L592-L628","documentation":"The SDK supports a before_file_upload hook. If the hook returns exactly False, the upload is deliberately cancelled and FileUploadAbortedError is raised — this is intentional user-configured rejection, not an infrastructure failure.","triggerScenarios":"Registering a before_file_upload callback (on a tool/toolkit/model level) that returns False for a given file — e.g. policy checks rejecting file types, size, or paths — and then triggering an upload via from_path for such a file.","commonSituations":"Content-policy hooks rejecting executable/media types; size guard hooks; hooks that accidentally return False (e.g. returning falsy values like None→handled, but a bare `return condition` that evaluates False) instead of the path string.","solutions":["If the rejection is unexpected, inspect your before_file_upload hook logic — it returned False; fix the condition or return the (possibly rewritten) path string instead.","If rejection is intended, catch FileUploadAbortedError and handle it as a policy outcome, not an error.","Make hook return types explicit: return path_in (str) to continue, False only to abort."],"exampleFix":"# before\ndef hook(source, **ctx):\n    return source.endswith('.pdf')  # returns False for .csv -> aborts\n# after\ndef hook(source, **ctx):\n    if not source.endswith('.pdf'):\n        return source  # continue with original path\n    return source","handlingStrategy":"try-catch","validationCode":"# before registering the hook, assert its return contract on sample inputs\nsample = 'notes.txt'\nout = my_hook(source=sample, tool='t', toolkit='k')\nassert out is False or isinstance(out, str), 'hook must return str or False'","typeGuard":"def hook_result_ok(out) -> bool:\n    return out is False or isinstance(out, str)","tryCatchPattern":"from composio.core.models._files import FileUploadAbortedError\n\ntry:\n    model = FileModel.from_path(client, path)\nexcept FileUploadAbortedError:\n    # policy rejection: log and skip, not a system error\n    logger.info('upload rejected by before_file_upload hook')","preventionTips":["Make before_file_upload always return the path string to continue; return False only for deliberate rejection.","Never return None or falsy values unintentionally (e.g. `return condition`).","Catch FileUploadAbortedError separately and treat it as expected control flow."],"tags":["python","hook","upload","aborted","user-config"],"backgroundTag":"hook-aborted-operation","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}