| name | obsidian-plugin-debug |
| description | Obsidian plugin debugging and troubleshooting guide. TRIGGER when: diagnosing plugin errors, investigating unexpected behavior, fixing runtime issues, analyzing console errors from Obsidian, or when the user mentions DevTools, console errors, plugin crashes, or mobile debugging. Also triggers on performance profiling and memory leak investigation in Obsidian plugins.
|
| user-invocable | false |
| allowed-tools | ["Read","Edit","Grep","Glob","Bash","Agent"] |
Obsidian Plugin Debugging
DevTools Access
| Platform | How to Open |
|---|
| Desktop (Mac) | Cmd+Option+I or View → Toggle Developer Tools |
| Desktop (Win/Linux) | Ctrl+Shift+I |
| Mobile | Not directly available — use console.log + desktop Vault copy |
Common Error Patterns
1. Plugin Fails to Load
Symptoms: Plugin doesn't appear, "Failed to load plugin" notice.
Check:
1. manifest.json — valid JSON? id matches directory name?
2. main.js — exists and is valid JS? (build may have failed)
3. minAppVersion — is user's Obsidian version >= this?
4. Default export — does main.ts `export default class ... extends Plugin`?
5. onload() — any synchronous throw before first await?
2. "Cannot read properties of undefined"
Almost always: accessing something before it's initialized or after it's destroyed.
async onload() {
const leaf = this.app.workspace.activeLeaf;
}
async onload() {
this.app.workspace.onLayoutReady(() => {
const leaf = this.app.workspace.activeLeaf;
});
}
3. Mobile-Only Failures
See mobile-debugging.md for:
- Common mobile-specific failures
- Debugging without DevTools
- iOS/Android platform differences
requestUrl HTTPS requirement on iOS
4. Memory Leaks
onload() {
document.addEventListener("click", this.handler);
}
onload() {
this.registerDomEvent(document, "click", this.handler);
}
Always use this.register*() methods. Manual listeners leak on plugin disable/enable cycles.
5. Race Conditions in Sync/Async
async triggerSync() {
const data = await this.loadData();
await this.saveData(data);
}
private syncing = false;
async triggerSync() {
if (this.syncing) return;
this.syncing = true;
try {
} finally {
this.syncing = false;
}
}
6. File Operation Errors
| Error | Cause | Fix |
|---|
| "File already exists" | vault.create() on existing file | Use vault.modify() or check with vault.getFileByPath() first |
| "File not found" | vault.modify() on non-existent file | Use vault.create() or check existence first |
| "Cannot delete" | File is open in editor | Close leaf first or use vault.trash() |
| Empty file after write | Writing empty string | Check content is not undefined/null |
7. API Deprecation Warnings
Check console for deprecation warnings. Common ones:
| Deprecated | Use Instead |
|---|
vault.adapter.exists() | vault.getFileByPath() returns null if missing |
Vault.recurseChildren() | vault.getFiles() + filter |
workspace.activeLeaf | workspace.getActiveViewOfType() |
FileSystemAdapter direct use | vault.adapter with type narrowing |
Debugging Workflow
- Reproduce — get exact steps, note if mobile-only or desktop-only
- Console first — check DevTools console for errors and stack traces
- Isolate — disable other plugins to rule out conflicts (
Safe Mode)
- Narrow — add
console.log at key points (onload, event handlers, API calls)
- Check API version — is
minAppVersion correct for APIs used?
- Test both platforms — desktop works != mobile works
Performance Debugging
console.time("scan");
const files = this.app.vault.getFiles();
console.timeEnd("scan");
Useful DevTools Commands
app.vault.getFiles().length
app.plugins.plugins["your-plugin-id"]
app.plugins.plugins["your-plugin-id"].settings
app.workspace.activeLeaf?.view
app.vault.adapter