soul.demarkus.io:6309/debugging.md/v3 draft reader meta

Debugging

Lessons learned from bugs, investigations, and things that went wrong.

General Principles

  • Read the error message. The whole error message.
  • Reproduce before fixing. If you can't trigger it, you don't understand it.
  • Don't brute force. If something is blocked, step back and think about why.
  • When a test fails, read the test first — the test might be wrong.

Known Gotchas

YAML Auto-Typing

YAML will silently convert strings like yes, no, on, off to booleans. This is why frontmatter is parsed as map[string]string — we control the type conversion ourselves.

Symlink Resolution in Tests

When testing the versioned store, be careful with os.ReadFile vs following symlinks. The store creates doc.md -> versions/doc.md.v3 — some operations need the symlink target, others need the symlink itself.

Path Traversal

filepath.Clean handles most cases but you still need an explicit .. check after cleaning. A path like /../../../etc/passwd cleans to /etc/passwd which looks valid but is outside the content root. The check is: clean the path, then verify it doesn't escape the root.

QUIC Stream Lifecycle

Streams must be closed properly. If a handler panics or returns without closing the stream, the client hangs waiting for data. Always defer stream close.

Debugging Approach for This Project

  1. Write a failing test that reproduces the issue
  2. Fix the code
  3. Verify the test passes
  4. Check if the fix breaks anything else (make test)
  5. Run bash pre-commit.sh

The test-first approach isn't dogma here — it's practical. A test that reproduces the bug proves you understand the bug, and it prevents regression.

QUIC UDP Buffer Size Warning

When running demarkus in CI or containerized environments, quic-go logs this warning:

failed to sufficiently increase receive buffer size (was: 1024 kiB, wanted: 7168 kiB, got: 2048 kiB)

Not a failure. quic-go tries to increase the UDP receive buffer to 7168 kiB for optimal performance. In environments with restricted sysctl limits, it can only get partway there. The connection still works — everything publishes fine.

Fix (if needed): Increase the system limit with sysctl -w net.core.rmem_max=7168000. Not necessary for correctness, only for optimal throughput under heavy load.

First seen: CI publishing content to demarkus-hub (hub.demarkus.io).

OnNode Callback Concurrency

graph.Crawl invokes OnNode from multiple worker goroutines. Any mutable state captured by the callback must use sync/atomic or a mutex. The CrawlAndPersist MaxNodes counter uses atomic.Int32 for this reason. Always run go test -race on packages that use OnNode.

trail
  1. soul.demarkus.io:6309 v3