stablyai/orca · error · Error
Unable to create untitled markdown note
Error message
Unable to create untitled markdown note
What it means
Thrown after the mobile session screen exhausts 100 attempts to create an 'untitled.md' (or untitled-N.md) file in a worktree without finding a free slot. Each iteration calls the host's 'files.createFile' RPC and bails to this generic message only when the loop completes without a successful create-and-open pair. It is a fallback for the unlikely case that every untitled-1..100.md already exists or every create call failed with a non-'file exists' error that did not throw.
Source
Thrown at mobile/app/h/[hostId]/session/[worktreeId].tsx:3843
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)
} finally {
setCreatingMarkdown(false)
}
}
async function handleCreateBrowser(rawUrl = 'about:blank'): Promise<boolean> {
if (!client || creatingBrowser) {
return false
}
// Why: read via ref so a tap before the capability probe resolves (or a stale callback) still sees the live value.
if (browserScreencastSupportedRef.current !== true) {
showToast('Desktop update required for mobile browser streaming', 1600)
return false
}View on GitHub (pinned to 1136503c6a)
Solutions
- Inspect the worktree directory and delete or rename the existing untitled-*.md files so a fresh slot is free.
- Check the host-side logs for the actual files.createFile errors; the generic message hides the per-attempt failure because non-'file exists' failures throw earlier with the host message.
- Verify the worktree is writable and not locked by another in-flight mutation (captureMobileFileMutationOwnership).
- If 100 slots is genuinely too few, raise the attempt ceiling or switch to a timestamp/UUID-based filename scheme.
Example fix
// before
for (let attempt = 1; attempt <= 100; attempt += 1) {
const relativePath = attempt === 1 ? 'untitled.md' : `untitled-${attempt}.md`
// ...
}
throw new Error('Unable to create untitled markdown note')
// after — include the last failure reason so the user can act on it
let lastReason = ''
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) {
lastReason = (createResponse as RpcFailure).error.message
if (isFileExistsErrorMessage(lastReason) && attempt < 100) continue
throw new Error(lastReason || 'Failed to create markdown note')
}
// ...
return
}
throw new Error(`Unable to create untitled markdown note: ${lastReason || 'all 100 slots taken'}`) Defensive patterns
Strategy: try-catch
Validate before calling
// Before invoking, pre-check the directory is not pre-saturated
const existing = await client.sendRequest('files.list', { worktree, relativePath: '.' }, { timeoutMs: 15_000 })
if (existing.ok) {
const names = (existing as RpcSuccess).result as { entries?: { name: string }[] }
const taken = new Set((names.entries ?? []).map(e => e.name).filter(n => /^untitled(-\d+)?\.md$/.test(n)))
// if all 100 slots taken, prompt user for a custom name instead of looping
} Type guard
function isOpenResponseOk(r: RpcSuccess | RpcFailure): r is RpcSuccess {
return r.ok
} Try / catch
try {
await handleCreateMarkdownNote()
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to create markdown note'
setCreateError(message)
showToast(message, 1800)
} finally {
setCreatingMarkdown(false)
} Prevention
- Avoid seeding worktrees with untitled-*.md files.
- Consider a UUID or timestamp suffix instead of a 1..100 counter to eliminate slot exhaustion.
- Surfaces the per-attempt host error in the final message so users can act on permissions/lock failures.
When it happens
Trigger: Reached only when `files.createFile` returns ok=false with a message that isFileExistsErrorMessage() recognizes 100 times in a row, or when createFile succeeds but the immediately-following `files.open` fails 100 times. The worktree is referenced as `id:${worktreeId}` via the client RPC.
Common situations: A worktree directory pre-populated with untitled.md through untitled-100.md (e.g. a test fixture, a generated docs folder, or a sync tool), or a host that rejects every createFile for reasons other than 'file exists' (permissions, read-only FS, worktree locked by another mutation).
Related errors
- Unable to load workspace metadata.
- Unable to read markdown
- Failed to save review notes
- Failed to create markdown note
- Unable to reach host
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/849c0859d85a2322.
Report an issue: GitHub.