Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LargeFileUploadTask fails when uploading an attachment to an Outlook item #691

Open
jasonjoh opened this issue Sep 24, 2024 · 2 comments
Open
Assignees
Labels
type:bug A broken experience

Comments

@jasonjoh
Copy link
Member

async def upload_attachment_to_message(graph_client: GraphServiceClient, file_path: str) -> None:
    # <UploadAttachmentSnippet>
    # Create message
    draft_message = Message(
        subject="Large attachment"
    )

    saved_draft = await graph_client.me.messages.post(draft_message)
    if saved_draft is None or saved_draft.id is None: return

    file_stream = open(file_path, 'rb')
    total_length = os.path.getsize(file_path)

    large_attachment = AttachmentItem(
        attachment_type=AttachmentType.File,
        name=os.path.basename(file_path),
        size=total_length
    )

    # import msgraph.generated.users.item.messages.item.attachments.create_upload_session.create_upload_session_post_request_body as attachment_upload
    upload_session_body = attachment_upload.CreateUploadSessionPostRequestBody(
        attachment_item=large_attachment
    )

    upload_session = await graph_client.me.messages.by_message_id(
        saved_draft.id).attachments.create_upload_session.post(upload_session_body)

    if upload_session is None: return

    # Max slice size must be a multiple of 320 KiB
    max_slice_size = 320 * 1024
    file_upload_task = LargeFileUploadTask(
        upload_session=upload_session,
        request_adapter=graph_client.request_adapter,
        stream=file_stream, # type: ignore
        max_chunk_size=max_slice_size,
        parsable_factory=FileAttachment #type:ignore
    )

    # Create a callback that is invoked after each slice is uploaded
    def progress_callback(uploaded_byte_range: tuple[int,int]):
        print(f'Uploaded {uploaded_byte_range[0]} bytes of {total_length} bytes\n')

    try:
        upload_result = await file_upload_task.upload(progress_callback)
        if upload_result.upload_succeeded and upload_result.item_response is not None:
            file_attachment: FileAttachment = upload_result.item_response
            print(f'Upload complete, attachment ID: {file_attachment.id}')
        else:
            print('Upload failed')
    except APIError as ex:
        print(f'Error uploading attachment: {ex.message}')

On the line upload_result = await file_upload_task.upload(progress_callback) an exception is thrown.

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 71, in <module>
    cli.main()
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 486, in main
    run()
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 336, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/home/jasonjoh/.vscode-server-insiders/extensions/ms-python.debugpy-2024.11.2024082901-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
    exec(code, run_globals)
  File "/home/jasonjoh/repos/msgraph-snippets-python/src/main.py", line 54, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/home/jasonjoh/repos/msgraph-snippets-python/src/main.py", line 45, in main
    await LargeFileUpload.run_all_samples(user_client, large_file_settings['largeFilePath'])
  File "/home/jasonjoh/repos/msgraph-snippets-python/src/snippets/large_file_upload.py", line 22, in run_all_samples
    await LargeFileUpload.upload_attachment_to_message(graph_client, file_path)
  File "/home/jasonjoh/repos/msgraph-snippets-python/src/snippets/large_file_upload.py", line 128, in upload_attachment_to_message
    upload_result = await file_upload_task.upload(progress_callback)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/msgraph_core/tasks/large_file_upload.py", line 95, in upload
    session = await self.next_chunk(
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/msgraph_core/tasks/large_file_upload.py", line 179, in next_chunk
    return await self.request_adapter.send_async(info, parsable_factory, error_map)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py", line 176, in send_async
    response = await self.get_http_response_message(request_info, parent_span)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py", line 542, in get_http_response_message
    return await self.retry_cae_response_if_required(resp, request_info, claims)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py", line 559, in retry_cae_response_if_required
    raise ValueError("Unable to parse claims from response")
ValueError: Unable to parse claims from response

My suspicion is that this is similar to the problem the Go SDK had in its initial implementation: it's sending an Authorization header with each upload request: microsoftgraph/msgraph-sdk-go-core#320

I can't confirm that this is the case, but it seems likely.

@jasonjoh jasonjoh added the status:waiting-for-triage An issue that is yet to be reviewed or assigned label Sep 24, 2024
@shemogumbe shemogumbe removed the status:waiting-for-triage An issue that is yet to be reviewed or assigned label Sep 25, 2024
@andrueastman andrueastman added the type:bug A broken experience label Oct 1, 2024
@shemogumbe shemogumbe self-assigned this Oct 14, 2024
@shemogumbe
Copy link
Contributor

shemogumbe commented Oct 28, 2024

Hello @jasonjoh this seems to not be related to the issue linked, this comonly occurs when a token is invalid or not passed at all.

Looking at the headers passed, Authorization token is not provided, If passed, the problem is actually solved.

@andrueastman
Copy link
Member

Hey @shemogumbe,

The outlook docs explicitly state that the authorization header should not be specified otherwise you will get an error. See https://learn.microsoft.com/en-us/graph/outlook-large-attachments?tabs=http#request-headers

I believe if we do not send the auth header, we should not get back a 401 response.

From the error shared, it looks like there's a difference in parsing the auth header for CAE as if there are no claims in the 401 responses, we should simply return the response back to the user (Which is a different issue)

https://github.com/microsoft/kiota-python/blob/72eb9438b495b5b6e6e641d0efa058faed52b30c/packages/http/httpx/kiota_http/httpx_request_adapter.py#L568

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug A broken experience
Projects
None yet
Development

No branches or pull requests

3 participants