{"record":{"id":"01ebeafa7c4cfbb8","repo":"stablyai/orca","slug":"preset-name-is-required","errorCode":null,"errorMessage":"Preset name is required.","messagePattern":"Preset name is required\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/repos.ts","lineNumber":2766,"sourceCode":"  try {\n    repoRemoteClientNotifier?.notifyReposChangedForRemoteClients()\n  } catch (err) {\n    // Why: a broadcast failure must never fail the mutation the user actually asked for.\n    console.error('[repos] failed to notify remote clients of repo change', err)\n  }\n  scheduleCurrentWorktreeBaseDirectoryWatcherSync()\n}\n\nfunction notifySparsePresetsChanged(mainWindow: BrowserWindow, repoId: string): void {\n  if (!mainWindow.isDestroyed()) {\n    mainWindow.webContents.send('sparsePresets:changed', { repoId })\n  }\n}\n\nfunction normalizeSparsePresetName(name: string): string {\n  const trimmed = name.trim()\n  if (!trimmed) {\n    throw new Error('Preset name is required.')\n  }\n  if (trimmed.length > 80) {\n    throw new Error('Preset name is too long.')\n  }\n  return trimmed\n}\n\nfunction normalizeSparsePresetDirectories(directories: string[]): string[] {\n  let normalized: string[]\n  try {\n    normalized = normalizeSparseDirectories(directories)\n  } catch (err) {\n    if (\n      err instanceof Error &&\n      err.message === 'Sparse checkout directories must be repo-relative paths.'\n    ) {\n      throw new Error('Preset directories must be repo-relative paths.')\n    }","sourceCodeStart":2748,"sourceCodeEnd":2784,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L2748-L2784","documentation":"Thrown by normalizeSparsePresetName when, after trimming, the name is empty. This runs inside the sparsePresets:save handler after the repo existence check, before length and directory validation. The cap is 80 characters (see 1290).","triggerScenarios":"Saving a preset with a blank name, a name of only whitespace, or a name field that was never populated by the form. The renderer did not enforce required-ness before the IPC call.","commonSituations":"Form submitted without validation; a default empty string placeholder leaked through; paste of whitespace-only content; programmatic save from a template missing the name field.","solutions":["Make the name input required and disable Save until a non-whitespace name is entered.","Trim and validate in the renderer (name.trim().length > 0) before invoking save.","Pre-fill a sensible default name (e.g. 'Preset ' + count) so empty submits are impossible.","On catch, focus the name field and show an inline validation message."],"exampleFix":"// before\nipc.invoke('sparsePresets:save', { repoId, name: nameInput, directories })\n\n// after\nconst name = nameInput.trim()\nif (!name) {\n  setError('Name is required')\n  return\n}\nipc.invoke('sparsePresets:save', { repoId, name, directories })","handlingStrategy":"validation","validationCode":"const name = rawName.trim()\nif (!name) {\n  setError('Preset name is required')\n  return\n}\nawait ipc.invoke('sparsePresets:save', { repoId, name, directories })","typeGuard":"function isNonEmptyName(value: unknown): value is string {\n  return typeof value === 'string' && value.trim().length > 0\n}","tryCatchPattern":"try {\n  await ipc.invoke('sparsePresets:save', { repoId, name, directories })\n} catch (e) {\n  if (/name is required/i.test((e as Error).message)) focusNameField()\n  else throw e\n}","preventionTips":["Make the name input required and disable Save until non-whitespace exists.","Trim in the renderer before sending.","Provide a default name so empty submits cannot happen."],"tags":["ipc","repos","sparse-checkout","preset","validation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}