{"record":{"id":"eaeb7f0dbddb1fd6","repo":"stablyai/orca","slug":"failed-to-create-markdown-note","errorCode":null,"errorMessage":"Failed to create markdown note","messagePattern":"Failed to create markdown note","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/app/h/[hostId]/session/[worktreeId].tsx","lineNumber":3829,"sourceCode":"    setCreatingMarkdown(true)\n    setCreateError('')\n\n    try {\n      const worktree = `id:${worktreeId}`\n      const mutationOwnership = await captureMobileFileMutationOwnership(client, worktree)\n      for (let attempt = 1; attempt <= 100; attempt += 1) {\n        const relativePath = attempt === 1 ? 'untitled.md' : `untitled-${attempt}.md`\n        const createResponse = await client.sendRequest(\n          'files.createFile',\n          { worktree, relativePath, ...mutationOwnership },\n          { timeoutMs: 15_000 }\n        )\n        if (!createResponse.ok) {\n          const message = (createResponse as RpcFailure).error.message\n          if (isFileExistsErrorMessage(message) && attempt < 100) {\n            continue\n          }\n          throw new Error(message || 'Failed to create markdown note')\n        }\n\n        const openResponse = await client.sendRequest(\n          'files.open',\n          { worktree, relativePath },\n          { timeoutMs: 15_000 }\n        )\n        if (!openResponse.ok) {\n          throw new Error((openResponse as RpcFailure).error.message)\n        }\n        scheduleDelayedAction(() => void fetchSessionTabs(), 300)\n        return\n      }\n      throw new Error('Unable to create untitled markdown note')\n    } catch (err) {\n      const message = err instanceof Error ? err.message : 'Failed to create markdown note'\n      setCreateError(message)\n      showToast(message, 1800)","sourceCodeStart":3811,"sourceCodeEnd":3847,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/app/h/[hostId]/session/[worktreeId].tsx#L3811-L3847","documentation":"Thrown in handleCreateMarkdownNote() when files.createFile RPC fails with a non-'file exists' error (or after 100 'file exists' attempts are exhausted) and the error message is empty. The function tries untitled.md through untitled-100.md, skipping EEXIST errors; this is the fallback when creation fails for another reason or with no message.","triggerScenarios":"files.createFile returns ok:false with a message that is not a file-exists error (isFileExistsErrorMessage returns false) or message is empty. Caused by: permission denied on the worktree; the worktree path being invalid; disk full; mutation ownership rejected; 100 untitled files already exist and the 100th also conflicts.","commonSituations":"A remote worktree where the mobile client lacks write permissions; the worktree was removed between session open and note creation; a full disk or quota on the host; mutation ownership token expired; a path traversal or invalid filename rejection.","solutions":["Check the desktop host logs for the files.createFile rejection reason when the message is empty.","Verify the worktree is writable and still exists — refresh the session if stale.","Ensure mutation ownership (captureMobileFileMutationOwnership) is valid before the create call.","If 100 untitled files exist, the user should clean up or the naming scheme should include a timestamp."],"exampleFix":"// before: empty message gives generic 'Failed to create markdown note'\nthrow new Error(message || 'Failed to create markdown note')\n\n// after: include RPC error code\nconst failure = createResponse as RpcFailure\nthrow new Error(\n  message ||\n  `Failed to create markdown note (code: ${failure.error.code ?? 'unknown'})`\n)","handlingStrategy":"retry","validationCode":"function buildCreateErrorMessage(createResponse) {\n  if (createResponse.ok) return null\n  const failure = createResponse as RpcFailure\n  return failure.error.message || `Failed to create markdown note (code: ${failure.error.code ?? 'unknown'})`\n}","typeGuard":"function isFileExistsError(message) {\n  return typeof message === 'string' && /exists|EEXIST/i.test(message)\n}","tryCatchPattern":"try {\n  for (let attempt = 1; attempt <= 100; attempt += 1) {\n    const createResponse = await client.sendRequest('files.createFile', { worktree, relativePath })\n    if (!createResponse.ok) {\n      const message = (createResponse as RpcFailure).error.message\n      if (isFileExistsError(message) && attempt < 100) continue\n      throw new Error(message || `Failed to create markdown note (code: ${(createResponse as RpcFailure).error.code ?? 'unknown'})`)\n    }\n    break\n  }\n} catch (err) {\n  setCreateError(err instanceof Error ? err.message : 'Failed to create markdown note')\n  showToast(err.message, 1800)\n}","preventionTips":["Use a timestamp-based filename to avoid the 100-attempt collision ceiling.","Verify mutation ownership is valid before the create loop.","Include the RPC error code in the fallback message for diagnosability.","Check the worktree is writable before attempting file creation."],"tags":["mobile","rpc","markdown","file-creation","worktree","server-error"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}