danielmiessler/Fabric · error · Error
responseData.error || 'Failed to save to Obsidian'
Error message
responseData.error || 'Failed to save to Obsidian'
What it means
Thrown in ChatInput.svelte when the POST to the Obsidian save endpoint returns non-ok. The real reason is in responseData.error from the server — typical causes are the Obsidian vault path not configured or not found, the notes directory missing, or a file write failure. If the server sends a non-JSON error page (e.g. a 404 HTML page from SvelteKit for a wrong route), response.json() itself throws before this line and you get a JSON parse error instead.
Source
Thrown at web/src/lib/components/chat/ChatInput.svelte:177
}
try {
const response = await fetch('/obsidian', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
pattern: $selectedPatternName,
noteName: $obsidianSettings.noteName,
content
})
});
const responseData = await response.json();
if (!response.ok) {
throw new Error(responseData.error || 'Failed to save to Obsidian');
}
// Add this after successful save
updateObsidianSettings({
saveToObsidian: false, // Reset the save flag
noteName: '' // Clear the note name
});
toastStore.success(responseData.message || `Saved to Obsidian: ${responseData.fileName}`);
} catch (error) {
console.error('Failed to save to Obsidian:', error);
toastStore.error(error instanceof Error ? error.message : 'Failed to save to Obsidian');
}
}
// Centralized language instruction logic in ChatService.ts; YouTube flow now passes plain transcript and system prompt
function extractYouTubeURLs(input: string): string[] {
const youtubePattern = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=[\w-]+(?:&[^\s]*)?|youtu\.be\/[\w-]+(?:\?[^\s]*)?)/gi;
return input.match(youtubePattern) || [];
}View on GitHub (pinned to 338b89cfe9)
Solutions
- Check the browser Network tab: read the actual status and responseData.error for the failed request
- Open Obsidian settings in the UI and confirm the vault path / note name are set and the vault directory exists on the machine running the server
- Verify the fetch URL matches the actual route (e.g. /api/obsidian/save) — a wrong path returns SvelteKit's HTML 404 and breaks response.json()
- Guard the JSON parse so non-JSON error bodies still produce a readable message
Example fix
// before
const responseData = await response.json();
if (!response.ok) {
throw new Error(responseData.error || 'Failed to save to Obsidian');
}
// after
const responseData = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(responseData?.error || `Failed to save to Obsidian (HTTP ${response.status})`);
} Defensive patterns
Strategy: validation
Validate before calling
// Run before POSTing the save
if (!$obsidianSettings.noteName?.trim()) {
toastStore.error('Set an Obsidian note name before saving');
return;
}
if (!('vaultPath' in $obsidianSettings && $obsidianSettings.vaultPath)) {
toastStore.error('Configure the Obsidian vault path first');
return;
} Try / catch
try {
const response = await fetch('/api/obsidian/save', { method: 'POST', ... });
const responseData = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(responseData?.error || `Failed to save to Obsidian (HTTP ${response.status})`);
}
toastStore.success(responseData.message || `Saved to Obsidian: ${responseData.fileName}`);
} catch (error) {
toastStore.error(error instanceof Error ? error.message : 'Failed to save to Obsidian');
} Prevention
- Complete Obsidian settings (vault path, note name) before enabling saveToObsidian
- json().catch(() => null) so HTML 404/500 pages degrade to a readable message
- Keep the fetch URL in sync with the actual route when refactoring endpoints
When it happens
Trigger: Saving a chat with Obsidian settings whose vault/base path is unset or wrong; the configured notes folder was moved or deleted; the endpoint route moved so the fetch hits SvelteKit's 404 handler (HTML body, json() throws); disk permission errors on the vault directory.
Common situations: First-time use without completing Obsidian settings, vault relocated after initial config, running the dev server against a different working directory so relative vault paths resolve elsewhere, endpoint path typo after a refactor.
Related errors
- HTTP error! status: ${response.status}
- HTTP_ERROR
- errorData.error || `HTTP error! status: ${response.status}`
- await response.text()
- Failed to load session: ${response.statusText}
AI-assisted analysis of danielmiessler/Fabric@338b89cfe9 (2026-08-15).
Data as JSON: /api/errors/744014724ff6b5af.
Report an issue: GitHub.