Why Record Mistakes
In the previous post, I introduced the content seed system. Prompts, ideas, and misses. The category for recording mistakes.
Why record mistakes?
First, to avoid repeating them. If you don’t record, you forget. And three months later, you struggle with the same thing.
Second, it helps others. Someone else can avoid the path I stumbled on.
Third, failure itself is good content. Failure stories teach more than success stories. They’re specific, practical, and relatable.
Here are three mistakes I made while building this blog.
Mistake 1: The Symlink Trap
I cloned the Hugo blog and ran hugo server. It worked. But posts weren’t showing up.
Checked the content/posts/ directory. No files. Strange. I definitely set this up before.
Turns out content/posts was a symlink:
ls -la content/posts
# lrwxr-xr-x content/posts -> /Users/deok/brainFucked/10-Blog/published
See the problem? Current user is koed, but the symlink points to /Users/deok/. The path from my old Mac was still there.
Why this happened:
- Copied dotfiles when setting up new Mac
- Cloned the git repo
- Symlink’s absolute path remained
- No error message - just looks like an empty directory
Solution:
rm content/posts
ln -s /Users/koed/Dev/BrainFucked/10-Blog/published content/posts
Lessons:
- Use relative path symlinks when possible
- After copying dotfiles to a new machine, check absolute paths
- “Nothing there” can be an error
Mistake 2: Bash’s Hidden Behavior
Made a test script. Counter increments when first test passes. But the script exits right after the first test. No error message.
#!/bin/bash
set -e # Exit immediately on error
TESTS_PASSED=0
log_success() {
echo "[PASS] $1"
((TESTS_PASSED++)) # Script dies here!
}
log_success "First test" # Only this prints, then exits
log_success "Second test" # Never reaches here
What happened:
((TESTS_PASSED++)) is an arithmetic expression. Its return value is the value before increment, not after.
- When
TESTS_PASSEDis 0 ((TESTS_PASSED++))returns 0- In Bash, 0 is falsy
- Because of
set -e, falsy return value → script exits
The irony of dying on first success.
Solution:
log_success() {
echo "[PASS] $1"
TESTS_PASSED=$((TESTS_PASSED + 1)) # This is safe
}
Lessons:
set -eand((var++))combination is dangerous- Silent exits without errors are hardest to debug
- Know the return values of Bash arithmetic operators
Mistake 3: Where to Put API Keys
Setting up OpenCode required an API key. First instinct was to put it in ~/.zshrc:
export GEMINI_API_KEY="sk-..."
But something felt off.
“putting api in shell config seems not good”
Right. There are problems:
- Key is exposed to all shell processes
- Could end up in history
- If dotfiles are git-managed, might accidentally commit
Better approach - macOS Keychain wrapper:
#!/bin/bash
# ~/bin/openclaw - wrapper script
fetch_key() {
local keychain_name="$1"
security find-generic-password -a "$USER" -s "$keychain_name" -w 2>/dev/null || {
echo "Error: $keychain_name not found in Keychain" >&2
return 1
}
}
export GEMINI_API_KEY=$(fetch_key "gemini-api-key") || exit 1
exec /path/to/actual/command "$@"
This way:
- Key is stored securely in Keychain
- Key is loaded into environment variable only during command execution
- Key disappears after command exits
- Not exposed to other processes
| Method | Key Exposure Scope |
|---|---|
| ~/.zshrc export | All shells, all processes |
| Wrapper script | Only during that command’s execution |
Lessons:
- Don’t put API keys in shell config files
- macOS Keychain is easier to use than you think
- The wrapper script pattern is universally useful
Why Record These Things
These three mistakes have something in common.
- Hard to find: No error messages or they’re vague
- Common: I’m not the only one who experiences them
- Forgotten if not recorded: I’ll struggle again in three months
That’s why I created the misses/ category in the content seed system. Record every mistake. Whether it becomes a blog post later or just personal reference.
To learn from failure, you must record failure.
Next Up
While organizing these mistakes, I discovered an interesting pattern. The process of building this blog was becoming blog content itself. Working while recording, and those records becoming content again.
In the next post, I’ll talk about the interesting pattern discovered through all of this.
All the mistakes in this post actually happened and were first recorded as misses/ seeds.
Series So Far
- Building a Blog with AI: The Beginning
- Learning from Failure: The Value of Small Mistakes
- Content Begets Content: Discovering Meta-Recursion
More to come…
