stablyai/orca · error · Error

Failed to create markdown note

Error message

Failed to create markdown note

What it means

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.

Source

Thrown at mobile/app/h/[hostId]/session/[worktreeId].tsx:3829

    setCreatingMarkdown(true)
    setCreateError('')

    try {
      const worktree = `id:${worktreeId}`
      const mutationOwnership = await captureMobileFileMutationOwnership(client, worktree)
      for (let attempt = 1; attempt <= 100; attempt += 1) {
        const relativePath = attempt === 1 ? 'untitled.md' : `untitled-${attempt}.md`
        const createResponse = await client.sendRequest(
          'files.createFile',
          { worktree, relativePath, ...mutationOwnership },
          { timeoutMs: 15_000 }
        )
        if (!createResponse.ok) {
          const message = (createResponse as RpcFailure).error.message
          if (isFileExistsErrorMessage(message) && attempt < 100) {
            continue
          }
          throw new Error(message || 'Failed to create markdown note')
        }

        const openResponse = await client.sendRequest(
          'files.open',
          { worktree, relativePath },
          { timeoutMs: 15_000 }
        )
        if (!openResponse.ok) {
          throw new Error((openResponse as RpcFailure).error.message)
        }
        scheduleDelayedAction(() => void fetchSessionTabs(), 300)
        return
      }
      throw new Error('Unable to create untitled markdown note')
    } catch (err) {
      const message = err instanceof Error ? err.message : 'Failed to create markdown note'
      setCreateError(message)
      showToast(message, 1800)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Check the desktop host logs for the files.createFile rejection reason when the message is empty.
  2. Verify the worktree is writable and still exists — refresh the session if stale.
  3. Ensure mutation ownership (captureMobileFileMutationOwnership) is valid before the create call.
  4. If 100 untitled files exist, the user should clean up or the naming scheme should include a timestamp.

Example fix

// before: empty message gives generic 'Failed to create markdown note'
throw new Error(message || 'Failed to create markdown note')

// after: include RPC error code
const failure = createResponse as RpcFailure
throw new Error(
  message ||
  `Failed to create markdown note (code: ${failure.error.code ?? 'unknown'})`
)
Defensive patterns

Strategy: retry

Validate before calling

function buildCreateErrorMessage(createResponse) {
  if (createResponse.ok) return null
  const failure = createResponse as RpcFailure
  return failure.error.message || `Failed to create markdown note (code: ${failure.error.code ?? 'unknown'})`
}

Type guard

function isFileExistsError(message) {
  return typeof message === 'string' && /exists|EEXIST/i.test(message)
}

Try / catch

try {
  for (let attempt = 1; attempt <= 100; attempt += 1) {
    const createResponse = await client.sendRequest('files.createFile', { worktree, relativePath })
    if (!createResponse.ok) {
      const message = (createResponse as RpcFailure).error.message
      if (isFileExistsError(message) && attempt < 100) continue
      throw new Error(message || `Failed to create markdown note (code: ${(createResponse as RpcFailure).error.code ?? 'unknown'})`)
    }
    break
  }
} catch (err) {
  setCreateError(err instanceof Error ? err.message : 'Failed to create markdown note')
  showToast(err.message, 1800)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/eaeb7f0dbddb1fd6. Report an issue: GitHub.