Skip to content

files.move_to / copy_to 500 on paths with spaces or reserved characters (raw path sent in JSON body) #124

Description

@andrii-novikov

Name and Version

aidial-client 0.14.0 (also reproduces on 0.12.0)

What steps will reproduce the bug?

  1. Have a DIAL file whose name contains a space (or any URL-reserved character), e.g. files/<bucket>/my file.txt.
  2. Call the move (or copy) operation:
from aidial_client import AsyncDial

client = AsyncDial(...)
await client.files.move_to(
    source="files/<bucket>/my file.txt",
    destination="files/<bucket>/renamed file.txt",
    overwrite=False,
)
  1. DIAL Core responds with 500.

Root cause. move_to / copy_to place the resolved path into the JSON body verbatim, whereas every other file operation places it into the request URL:

# move_to / copy_to (resources/files.py) — path goes into the body
json_data={
    "sourceUrl": self.get_api_path(str(source)),         # 'files/<bucket>/my file.txt'  ← raw space
    "destinationUrl": self.get_api_path(str(destination)),
    "overwrite": overwrite,
}

# upload / download / delete — path goes into the URL
url=urljoin(API_PREFIX, self.get_api_path(str(url)))

get_api_path returns the path unencoded (a literal space is preserved). For upload/download/delete that is harmless because httpx percent-encodes the URL path on the wire (my file.txtmy%20file.txt), so DIAL Core receives a valid resource URL. For move_to/copy_to the value sits in a JSON string, where nothing encodes it, so DIAL Core's ops/resource/move and ops/resource/copy endpoints receive a raw space in a field they parse as a percent-encoded resource URL, and 500.

Verification:

>>> from aidial_client.helpers.storage_resource import safe_parse_storage_resource
>>> safe_parse_storage_resource(url='files/mybucket/my file.txt', dial_api_url='http://core/v1/').api_path
'files/mybucket/my file.txt'   # literal space kept — fine in a URL slot, broken in a body slot

Any URL-reserved character in a filename triggers this (space, #, ?, %, …), not only spaces.

What is the expected behavior?

move_to / copy_to succeed for any valid filename, consistent with upload / download / delete. The sourceUrl / destinationUrl values sent in the JSON body should be percent-encoded resource URLs (e.g. files/<bucket>/my%20file.txt), matching what DIAL Core receives for the other operations.

What do you see instead?

A 500 from DIAL Core whenever the source or destination path contains a space or other URL-reserved character. Filenames without reserved characters work correctly.

Additional information

The other file operations avoid the problem only incidentally, because httpx encodes the URL path — the body path is never encoded. A fix should percent-encode the path when building the sourceUrl / destinationUrl body fields for both the sync and async move_to / copy_to, preserving / separators (e.g. urllib.parse.quote(path, safe="/")).

Affected: both Files (sync) and AsyncFiles in aidial_client/resources/files.py.

Source bug: epam/ai-dial-quickapps-backend#447

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions