-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Bug Description
VikingFS.mkdir() (openviking/storage/viking_fs.py lines 141–153) calls _ensure_parent_dirs(path) to create parent directories, but never calls self.agfs.mkdir(path) to create the target directory itself. The method returns silently — every mkdir() call is effectively a no-op.
async def mkdir(self, uri: str, mode: str = "755", exist_ok: bool = False) -> None:
path = self._uri_to_path(uri)
await self._ensure_parent_dirs(path) # Only creates parents
if exist_ok:
try:
await self.stat(uri)
return None # Already exists, return
except Exception:
pass # Does not exist, fall through
return # ====== target directory never created ======_ensure_parent_dirs (lines 656–670) iterates range(1, len(parts)), creating components 0 through N-2 (all parents), but NOT the final component (the target directory).
Steps to Reproduce
import openviking as ov
import asyncio
client = ov.SyncOpenViking(path="./data")
client.initialize()
viking_fs = client.viking_fs
test_uri = "viking://resources/bug1_test_dir"
# Call mkdir
asyncio.run(viking_fs.mkdir(test_uri, exist_ok=False))
# Returns without error
# Verify directory exists
asyncio.run(viking_fs.stat(test_uri))
# Raises AGFSClientError: no such file or directory: /resources/bug1_test_dir
client.close()Can also be verified via pure logic analysis:
path = "/local/resources/new_project"
parts = path.lstrip("/").split("/")
# parts = ["local", "resources", "new_project"]
for i in range(1, len(parts)): # i = 1, 2
parent = "/" + "/".join(parts[:i])
print(f"agfs.mkdir({parent})")
# Output:
# agfs.mkdir(/local)
# agfs.mkdir(/local/resources)
# "/local/resources/new_project" is never createdExpected Behavior
await viking_fs.mkdir("viking://resources/new_project") should create the target directory /local/resources/new_project via self.agfs.mkdir(path).
Actual Behavior
The directory is never created. The method returns silently. Subsequent stat calls raise:
AGFSClientError: no such file or directory: /resources/bug1_test_dir
Verified on Windows + Python 3.13.7.
Minimal Reproducible Example
import openviking as ov
import asyncio
client = ov.SyncOpenViking(path="./data")
client.initialize()
viking_fs = client.viking_fs
asyncio.run(viking_fs.mkdir("viking://resources/test_dir", exist_ok=False))
# No error
asyncio.run(viking_fs.stat("viking://resources/test_dir"))
# AGFSClientError: no such file or directory: /resources/test_dir
client.close()Error Logs
[2] Calling viking_fs.mkdir('viking://resources/bug1_test_dir', exist_ok=False)...
[2] mkdir returned without error
[3] Calling viking_fs.stat('viking://resources/bug1_test_dir') to verify...
[3] stat raised: AGFSClientError: no such file or directory: /resources/bug1_test_dir
Conclusion: BUG confirmed — mkdir() is a no-op, directory was never createdOpenViking Version
0.1.10 (main branch, 2026-02-07)
Python Version
3.13.7
Operating System
Windows
Model Backend
Other
Additional Context
The missing line should be await asyncio.to_thread(self.agfs.mkdir, path) before the final return.
This bug affects all code paths that rely on VikingFS.mkdir(), including:
TreeBuilder._move_directory_in_agfs(line 163)DirectoryInitializerimport_ovpack
The system may appear to work in some cases only because write_file independently calls _ensure_parent_dirs, which creates intermediate directories as a side effect.