koodo-reader/koodo-reader · error · Error

Failed to create directory: ${part}

Error message

Failed to create directory: ${part}

What it means

ensureDirectoryExists() walks each path segment of folderPath, calling getDirectoryHandle(part, {create:true}) on the current handle. If any segment cannot be created or opened, it logs the underlying error and rethrows this sanitized 'Failed to create directory: <part>' error naming the offending segment. Common underlying causes are invalid characters in the segment name, name collisions with an existing file, or OS-level permission failures.

Source

Thrown at src/utils/file/localFile.ts:312

    const pathParts = normalizedPath
      .split("/")
      .filter((part) => part.length > 0);

    let currentHandle = baseHandle;

    for (const part of pathParts) {
      try {
        // 尝试获取现有文件夹
        currentHandle = await currentHandle.getDirectoryHandle(part);
      } catch (error) {
        // 如果文件夹不存在,创建新文件夹
        try {
          currentHandle = await currentHandle.getDirectoryHandle(part, {
            create: true,
          });
        } catch (createError) {
          console.error(`Error creating directory ${part}:`, createError);
          throw new Error(`Failed to create directory: ${part}`);
        }
      }
    }

    return currentHandle;
  }

  // 保存文件到本地目录(支持指定文件夹)
  static async saveFile(
    filename: string,
    content: string | ArrayBuffer,
    folderPath?: string
  ): Promise<boolean> {
    try {
      const directoryHandle = await this.getStoredDirectoryHandle();
      if (!directoryHandle) {
        throw new Error("No directory access permission");
      }

View on GitHub (pinned to 7d40df41e0)

Solutions

  1. Sanitize folderPath segments before calling saveFile: strip reserved characters (<>:"/\\|?*), trim, and collapse empty segments
  2. Split the path yourself and create directories one level at a time to identify the failing segment
  3. Check the console.error line above the throw — it logs the original createError with the real OS reason
  4. Ensure the segment does not collide with an existing file of the same name in the parent directory

Example fix

// before
await LocalFileService.saveFile(content, fileName, `books/${book.title}/covers`);
// after
const safeTitle = book.title.replace(/[<>:"/\\|?*]/g, "_").trim();
const folderPath = ["books", safeTitle, "covers"].filter(Boolean).join("/");
await LocalFileService.saveFile(content, fileName, folderPath);
Defensive patterns

Strategy: validation

Validate before calling

function sanitizeFolderPath(p: string): string {
  return p
    .split("/")
    .map((seg) => seg.replace(/[<>:"\\|?*\x00-\x1f]/g, "_").trim())
    .filter(Boolean)
    .join("/");
}
// usage: saveFile(content, name, sanitizeFolderPath(rawPath))

Type guard

function isSafeSegment(seg: string): boolean {
  return seg.length > 0 && seg.length < 255 && !/[<>:"\\|?*\/\x00-\x1f]/.test(seg);
}

Try / catch

try {
  await LocalFileService.saveFile(content, name, path);
} catch (e) {
  if (e.message.startsWith("Failed to create directory:")) {
    const badPart = e.message.split(":")[1]?.trim();
    console.warn("sanitize and retry for segment:", badPart);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling saveFile(content, fileName, folderPath) where folderPath contains a segment with filesystem-illegal characters (e.g. ':' or '\\' on Windows, '/' mid-segment), a segment name matching an existing FILE in the parent directory, an empty segment from a malformed path like 'a//b', or a name too long for the OS.

Common situations: Folder paths derived from book titles/authors containing reserved characters, nested paths built by string concatenation with accidental double slashes, or saving into a synced/locked directory (OneDrive, network share) that rejects creation.

Related errors


AI-assisted analysis of koodo-reader/koodo-reader@7d40df41e0 (2026-08-29). Data as JSON: /api/errors/c06e65bc4bd1da46. Report an issue: GitHub.