Fix doc-sync auth failure
Symptom

Morning email arrives but ~/Sync/ED/.doc-sync-log/YYYY-MM-DD.md is ~300 bytes containing one of:

  • Failed to authenticate. API Error: 401 The socket connection was closed unexpectedly...
  • Failed to authenticate. API Error: 401 <html><head><title>502 Bad Gateway</title>...cloudflare</html>
  • The Gotify alert: โš ๏ธ Doc-Sync YYYY-MM-DD โ€” AUTH FAILED

The CLI mis-reports the real cause as “401” regardless of the underlying issue. The most likely cause is a corrupted API key file, not an actual auth-server problem.

Diagnose
# Inspect the key file โ€” look for any garbage prefix
head -c 25 ~/.config/anthropic-api-key
echo

# Check file size โ€” a clean key is exactly 108 bytes (no trailing newline)
wc -c ~/.config/anthropic-api-key

If the file starts with anything other than sk-ant-api03-, it’s corrupted. The historical bug was a literal -n prefix from a manual echo -n "$KEY" > file in a shell where -n was printed instead of treated as a flag.

Test the key directly against the API:

KEY=$(cat ~/.config/anthropic-api-key)
curl -s -o /dev/null -w 'HTTP %{http_code}\n' \
    -H "x-api-key: $KEY" \
    -H 'anthropic-version: 2023-06-01' \
    https://api.anthropic.com/v1/models

HTTP 200 = key works. HTTP 401 = key is bad.

Fix

Rewrite the file cleanly with printf (which doesn’t have the -n ambiguity):

# Back up the broken version first
cp ~/.config/anthropic-api-key ~/.config/anthropic-api-key.bak.$(date +%Y%m%d-%H%M%S)

# Get the key from your password manager / wherever it lives, then:
printf '%s' 'sk-ant-api03-...' > ~/.config/anthropic-api-key
chmod 600 ~/.config/anthropic-api-key

# Verify
ls -la ~/.config/anthropic-api-key   # should show 108 bytes, mode 600
head -c 25 ~/.config/anthropic-api-key  # should start with sk-ant-api03-

Never use echo -n to write the key โ€” different shells handle -n differently and some write it as a literal prefix.

Verify

Run doc-sync manually with yesterday’s date:

~/Sync/ED/skills/doc-sync/scripts/run.sh
tail -30 ~/Sync/ED/.doc-sync-log/.last-run.log

You should see Auth precheck OK (HTTP 200) in the log and the report should be 5โ€“20 KB (not 300 bytes).

Why this is already hardened

As of 2026-05-25, run.sh has two defenses:

  1. Strip on load โ€” sed -E 's/^-n[[:space:]]+//; s/[[:space:]]+$//' removes a stray -n prefix and any trailing whitespace before using the key.
  2. Step 0 fail-fast precheck โ€” single /v1/models request with --max-time 15. If it returns non-200, writes the actual cause to the day’s report, Gotify-alerts at priority 8, and exits 1 instead of burning 5+ minutes on a 1 MB prompt.

So the failure mode going forward should be a clear error inside 15 seconds, not a silent stub at 3 AM.