brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
obsidian-common-errorsDiagnose and fix common Obsidian plugin errors and exceptions. Use when encountering plugin errors, debugging failed operations, or troubleshooting Obsidian plugin issues. Trigger with phrases like "obsidian error", "fix obsidian plugin", "obsidian not working", "debug obsidian plugin".
Independent GitHub snapshot · Automated classification · Original documentation governs
Quick reference for the most common Obsidian plugin errors and their solutions.
Press Ctrl+Shift+I (Windows/Linux) or Cmd+Option+I (macOS) to open Developer Tools.
Check the Console tab for red error messages related to your plugin.
Find your error type and apply the fix.
Error Message:
TypeError: Cannot read properties of undefined (reading 'xyz')
Cause: Accessing a property on a null/undefined object, often when vault or workspace isn't ready.
Solution:
// WRONG: Direct access without check
const file = this.app.workspace.getActiveFile();
const content = await this.app.vault.read(file); // Error if file is null
// RIGHT: Null check first
const file = this.app.workspace.getActiveFile();
if (!file) {
new Notice('No file is currently open');
return;
}
const content = await this.app.vault.read(file);
Error Message:
Plugin 'my-plugin' failed to load
Causes and Solutions:
# Check for syntax errors
node -c main.js
{
"id": "my-plugin", // Required: unique identifier
"name": "My Plugin", // Required: display name
"version": "1.0.0", // Required: semver version
"minAppVersion": "1.0.0", // Required: minimum Obsidian version
"description": "...", // Required
"author": "Your Name" // Required
}
// WRONG: Named export
export class MyPlugin extends Plugin { }
// RIGHT: Default export
export default class MyPlugin extends Plugin { }
Error Message:
This plugin failed to load and has been disabled. Check the developer console for more information.
Common Causes:
// WRONG: Error thrown during load
async onload() {
const data = await someAsyncOperation(); // Throws if fails
}
// RIGHT: Wrap in try-catch
async onload() {
try {
const data = await someAsyncOperation();
} catch (error) {
console.error('Failed to load data:', error);
new Notice('Plugin initialization failed');
}
}
// WRONG: Importing from wrong package
import { Something } from 'wrong-package';
// RIGHT: Check external modules in build config
// esbuild.config.mjs
external: ['obsidian', 'electron', '@codemirror/*', '@lezer/*'],
Error Message:
Command 'my-plugin:my-command' not found
Cause: Command not registered or wrong command ID.
Solution:
// Verify command registration
this.addCommand({
id: 'my-command', // ID without plugin prefix
name: 'My Command',
callback: () => {
// Handler
},
});
// Obsidian automatically prefixes with plugin ID:
// Full ID becomes: 'my-plugin:my-command'
Error Message:
View type 'custom-view' not registered
Cause: Trying to use a view before registering it.
Solution:
// MUST register view in onload, BEFORE using it
async onload() {
// 1. Register view type first
this.registerView(
VIEW_TYPE_CUSTOM,
(leaf) => new CustomView(leaf)
);
// 2. Then you can activate it
this.addCommand({
id: 'open-view',
name: 'Open View',
callback: () => this.activateView(), // Now safe to call
});
}
Error Message: No error, but settings reset on reload.
Cause: Missing saveData() call or wrong data structure.
Solution:
// WRONG: Modifying settings without saving
this.settings.myOption = newValue;
// RIGHT: Save after modifying
this.settings.myOption = newValue;
await this.saveSettings();
// Implement save properly:
async saveSettings() {
await this.saveData(this.settings);
}
async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData()
);
}
Error Message:
Error: ENOENT: no such file or directory
Cause: Incorrect file path or file doesn't exist.
Solution:
// Always verify file exists
const file = this.app.vault.getAbstractFileByPath(path);
if (!file) {
new Notice(`File not found: ${path}`);
return;
}
if (!(file instanceof TFile)) {
new Notice(`Not a file: ${path}`);
return;
}
// Now safe to use
const content = await this.app.vault.read(file);
Symptoms: Plugin slows down, duplicate events firing.
Cause: Event listeners not properly removed.
Solution:
// WRONG: Direct event listener
document.addEventListener('click', this.handleClick);
// RIGHT: Use registerDomEvent (auto-cleanup)
this.registerDomEvent(document, 'click', this.handleClick.bind(this));
// WRONG: Direct workspace event
this.app.workspace.on('file-open', callback);
// RIGHT: Use registerEvent (auto-cleanup)
this.registerEvent(
this.app.workspace.on('file-open', callback)
);
Error Message:
Cannot find module 'obsidian' or its corresponding type declarations
Solution:
# Verify obsidian types are installed
npm install obsidian@latest
# Check tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node",
"types": ["node"]
}
}
# Note: 'obsidian' is external - not bundled
# Check esbuild.config.mjs
external: ['obsidian'],
// Add at top of main.ts for debugging
const DEBUG = true;
function debug(...args: any[]) {
if (DEBUG) {
console.log('[MyPlugin]', ...args);
}
}
// Use throughout code
debug('Loading settings', this.settings);
debug('Processing file', file.path);
// Add debug commands during development
this.addCommand({
id: 'debug-dump-settings',
name: 'Debug: Dump Settings',
callback: () => {
console.log('Settings:', JSON.stringify(this.settings, null, 2));
}
});
this.addCommand({
id: 'debug-list-views',
name: 'Debug: List Open Views',
callback: () => {
const leaves = this.app.workspace.getLeavesOfType('markdown');
console.log('Open views:', leaves.length);
leaves.forEach(leaf => {
console.log('-', leaf.view.file?.path);
});
}
});
obsidian-debug-bundleFor comprehensive debugging, see obsidian-debug-bundle.