# Error Log

> Captures non-obvious errors and their solutions as structured Obsidian notes for future reference. Use when: (1) /error-log command to capture an error from the current session, (2) /error-log <error description> to log a specific error, (3) user wants to document a tricky bug fix or error resolution.

- Skill: `abhattacherjee/error-log` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add abhattacherjee/error-log`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abhattacherjee/error-log/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: abhattacherjee (https://skillmd.com/u/abhattacherjee)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abhattacherjee/error-log

---


# Error Log — Capture Error Solutions to Obsidian

Analyze the current conversation for error -> investigation -> fix patterns, structure them as reusable troubleshooting notes, and save to the Obsidian vault.

**Tools needed:** Bash, Write, Read

## Procedure

Follow these steps exactly. Do not skip steps or reorder them.

### Step 1 — Read config

Run:

```bash
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
python3 -c '
import sys, os
import glob; sys.path.insert(0, max(glob.glob(os.path.expanduser("~/.claude/plugins/cache/*/obsidian-brain/*/hooks")), default="hooks"))
from obsidian_utils import load_config
c = load_config()
if not c.get("vault_path"):
    print("ERROR: vault_path not configured", file=sys.stderr)
    sys.exit(1)
print("VAULT=" + c["vault_path"])
print("SESS=" + c.get("sessions_folder", "claude-sessions"))
print("INS=" + c.get("insights_folder", "claude-insights"))
'
```

Parse each output line as KEY=VALUE, splitting on the first `=`.

If the file does not exist or is invalid JSON, tell the user:

> Config not found. Please run `/obsidian-setup` first to configure your Obsidian vault.

Stop here if config is missing.

### Step 2 — Validate vault access

Run:

```bash
test -d "$VAULT_PATH/$INSIGHTS_FOLDER" && test -w "$VAULT_PATH/$INSIGHTS_FOLDER" && echo "OK" || echo "FAIL"
```

If FAIL, tell the user:

> The insights folder `$VAULT_PATH/$INSIGHTS_FOLDER` does not exist or is not writable. Run `/obsidian-setup` to fix this.

Stop here if FAIL.

### Step 3 — Identify the error

Check if the user provided an argument after `/error-log`.

- **With argument** (e.g. `/error-log BrokenPipeError in subprocess`): Use the description to search the current conversation for matching error context, investigation steps, and resolution.
- **Without argument** (bare `/error-log`): Scan the full conversation for error -> investigation -> fix patterns. Look for:
  - Stack traces, error messages, or exception output
  - Debugging steps taken (hypothesis, investigation, failed attempts)
  - The fix that ultimately resolved the issue
  - If multiple errors were resolved, present a numbered list and ask the user which to log

If no error pattern is found in the conversation, tell the user:

> No error -> fix pattern detected in this session. You can run `/error-log <description>` to manually describe an error to document.

Stop here if no error is found.

### Step 4 — Structure the error note

Draft the note body with these four sections. Each section should be concise but complete enough to be useful months later when encountering the same error:

- **Error:** The exact error message, symptoms, and context where it appeared (include relevant stack trace snippets or command output if available, formatted as code blocks)
- **Root Cause:** Why the error happened — the underlying reason, not just the surface symptom
- **Fix:** The specific change or command that resolved it — include code diffs, config changes, or commands as code blocks
- **Prevention:** How to avoid this error in the future — linting rules, config patterns, pre-checks, or design principles

### Step 5 — Auto-generate topic tags

Based on the error content, generate 1-3 topic tags. Tags should be lowercase, hyphenated, and specific to the technology or domain. Examples:

- `claude/topic/subprocess-pipes`
- `claude/topic/python-async`
- `claude/topic/npm-dependencies`
- `claude/topic/git-hooks`

### Step 6 — Show preview and ask for edits

Present the full note to the user including frontmatter:

```
---
type: claude-error-fix
date: YYYY-MM-DD
created_at: <ISO-8601-UTC>
source_session: <current-session-id>
source_session_note: "[[<session-note-filename>]]"
project: <project-name>
tags:
  - claude/error-fix
  - claude/project/<project-name>
  - claude/topic/<auto-generated-topic-1>
  - claude/topic/<auto-generated-topic-2>
---

# <Error Title>

## Error

<error message and symptoms>

## Root Cause

<why it happened>

## Fix

<what resolved it>

## Prevention

<how to avoid it in future>
```

Where:
- `YYYY-MM-DD` is today's date
- `<ISO-8601-UTC>` is the current UTC timestamp at second precision. Get it via:
  ```bash
  python3 -c 'from datetime import datetime, timezone; print(datetime.now(timezone.utc).isoformat(timespec="seconds"))'
  ```
  Example: `2026-04-24T18:42:11+00:00`
- `<current-session-id>` and `<session-note-filename>` are derived together. Get session context via the shared helper:

  ```bash
  cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
  python3 -c '
  import sys, os
  import glob; sys.path.insert(0, max(glob.glob(os.path.expanduser("~/.claude/plugins/cache/*/obsidian-brain/*/hooks")), default="hooks"))
  from obsidian_utils import load_config, get_session_context
  c = load_config()
  ctx = get_session_context(c["vault_path"], c.get("sessions_folder", "claude-sessions"))
  print("SID=" + ctx["session_id"] + " HASH=" + ctx["hash"] + " PROJECT=" + ctx["project"] + " SESSION_NOTE=" + ctx["session_note_name"])
  '
  ```

  Parse the output to get `SESSION_ID`, `HASH`, `PROJECT`, and `SESSION_NOTE`.

  **Important:** If `SESSION_ID` is `unknown`, use `unknown` for `source_session` and omit `source_session_note` entirely.
- `<project-name>` is the `PROJECT` value from `get_session_context()` (lowercased, hyphenated basename of cwd)
- `<Error Title>` is a short, descriptive title for the error (e.g. "BrokenPipeError when piping subprocess output to head")
- The `source_session_note` field creates an Obsidian backlink to the source session note

Ask the user:

> Preview above. Would you like to:
> - **save** as-is
> - **edit tags** — add or remove tags
> - **edit content** — tell me what to change
> - **cancel** — discard this note

Wait for the user's response. Apply any requested edits and show the updated preview. Repeat until the user says **save** or **cancel**.

If cancel, stop here.

### Step 7 — Generate filename

Construct the filename from these parts:

1. **Date:** `YYYY-MM-DD` (today)
2. **Slug:** The error title, lowercased, spaces replaced with hyphens, non-alphanumeric characters (except hyphens) removed, truncated to 50 characters
3. **Hash:** 4-character hex hash derived from the current timestamp: `date +%s | md5 | cut -c29-32` (macOS) or `date +%s | md5sum | cut -c1-4` (Linux). Do NOT use `tail -c 4` — it counts the trailing newline as a byte and returns only 3 visible characters.
4. **Suffix:** `-error`

Final filename: `YYYY-MM-DD-<slug>-<hash>-error.md`

Example: `2026-04-04-brokenpipeerror-subprocess-pipe-a3f2-error.md`

### Step 8 — Write the note

Run:

```bash
mkdir -p "$VAULT_PATH/$INSIGHTS_FOLDER"
```

Then use the **Write** tool to write the full note (frontmatter + body) to:

```
$VAULT_PATH/$INSIGHTS_FOLDER/YYYY-MM-DD-<slug>-<hash>-error.md
```

Then set permissions:

```bash
chmod 644 "$VAULT_PATH/$INSIGHTS_FOLDER/YYYY-MM-DD-<slug>-<hash>-error.md"
```

### Step 9 — Confirm

Print:

> **Error fix logged!**
> - File: `$VAULT_PATH/$INSIGHTS_FOLDER/<filename>`
> - Tags: `claude/error-fix`, `claude/project/<name>`, `claude/topic/<topic1>`, ...
> - Open in Obsidian to view. This note will appear in the "Error Fixes" section of the Project Index dashboard.

