sinelaw/fresh · error

no such folder

Error message

no such folder: ${parentId}

What it means

apiCreateFolder validates the optional parent folder id: if a parent is supplied (non-null) but no folder with that id exists, it throws. This prevents creating a folder under a dangling parent reference. Unlike the name check, the parent is genuinely optional — pass null (or omit) to create a top-level folder.

Solutions

  1. Confirm the parent id exists via the folder list before creating under it
  2. Pass null (or omit the argument) to create a top-level folder
  3. Re-sync folder ids after any delete/rename from another client or session

Example fix

// before
api.createFolder(name, staleParentId);
// after
const parentId = staleParentId && api.listFolders().some(f => f.id === staleParentId)
  ? staleParentId
  : null;
api.createFolder(name, parentId);
Defensive patterns

Strategy: validation

Validate before calling

const parents = api.listFolders();
if (parentId != null && !parents.some(f => f.id === parentId)) {
  parentId = null; // fall back to top-level
}

Type guard

function isKnownParent(id, folders) {
  return id == null || folders.some(f => f.id === id);
}

Try / catch

try {
  api.createFolder(name, parentId);
} catch (e) {
  if (String(e).startsWith("no such folder")) {
    api.createFolder(name, null); // create at top level instead
  } else throw e;
}

Prevention

When it happens

Trigger: Calling apiCreateFolder(name, parentId) where parentId was deleted, never existed, or is stale from a previous run; passing the empty string or a placeholder value instead of null for 'no parent'.

Common situations: Scripts caching folder ids across sessions after the parent was removed; another client concurrently deleting the parent; passing "" as parent when null was meant.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/5930d92aa30796e4. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/plugins/orchestrator.ts:10645

    for (const f of childFoldersOf(parent)) {
      out.push({ folderId: f.id, name: f.name, parent: f.parent ?? null, depth });
      walk(f.id, depth + 1);
    }
  };
  walk(null, 0);
  return out;
}

function apiCreateFolder(name: string, parent?: string | null): string {
  const clean = trimmed(name);
  // The dialog falls back to "New Folder" on an empty submit because a human
  // who typed nothing meant "just make me one". A caller passing an empty
  // string meant something else — most likely a variable that didn't hold
  // what they thought — so it is an error rather than a silent default.
  if (!clean) throw new Error("folder name must not be empty");
  const parentId = parent ?? null;
  if (parentId !== null && !folderById(parentId)) {
    throw new Error(`no such folder: ${parentId}`);
  }
  const id = createFolder(clean, parentId);
  refreshDockTree();
  return id;
}

function apiRenameFolder(folderId: string, name: string): boolean {
  if (!folderById(folderId)) return false;
  const clean = trimmed(name);
  if (!clean) throw new Error("folder name must not be empty");
  renameFolder(folderId, clean);
  refreshOpenDialog();
  return true;
}

function apiDeleteFolder(folderId: string): boolean {
  if (!folderById(folderId)) return false;
  // `deleteFolder` reparents the subtree one level up, so nothing inside is

View on GitHub (pinned to 67894ca546)