This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# Heading resolver broken: `Target-Type: heading` PATCH and `GET /heading/...` both fail on any valid heading (4.1.1)
|
||||
|
||||
## Summary
|
||||
|
||||
In Obsidian Local REST API **4.1.1**, two endpoints that both rely on heading resolution always fail, even on a freshly written file with trivially-valid markdown headings:
|
||||
|
||||
- `PATCH /vault/<path>` with `Target-Type: heading` → HTTP 400 `invalid-target`
|
||||
- `GET /vault/<path>/heading/<heading-text>` → HTTP 404 `Not Found`
|
||||
|
||||
`Target-Type: frontmatter` PATCH on the same file works fine, so the PATCH route itself is healthy. The bug is isolated to the heading-resolution code path shared by these two endpoints.
|
||||
|
||||
Also reproduced in **3.6** before upgrading; the 3.6 → 4.1.1 upgrade did not change the behavior.
|
||||
|
||||
## Minimal reproducer
|
||||
|
||||
The setup writes a clean file with LF-only line endings, then exercises both heading endpoints and one frontmatter endpoint as a control.
|
||||
|
||||
```bash
|
||||
HOST="https://YOUR-HOST:27124"
|
||||
KEY="YOUR_API_KEY"
|
||||
|
||||
# 1. PUT a fresh, simple file (HTTP 204 expected)
|
||||
cat > /tmp/repro.md <<'EOF'
|
||||
---
|
||||
type: scratch
|
||||
---
|
||||
|
||||
# Hello
|
||||
|
||||
## Section A
|
||||
|
||||
Content under A.
|
||||
|
||||
## Section B
|
||||
|
||||
Content under B.
|
||||
EOF
|
||||
|
||||
curl -sk -w "PUT: %{http_code}\n" -X PUT \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
-H "Content-Type: text/markdown" \
|
||||
--data-binary @/tmp/repro.md \
|
||||
"$HOST/vault/scratch/repro.md"
|
||||
|
||||
# 2. PATCH append under heading "Section A" — expected 200, actual 400 invalid-target
|
||||
echo "appended" > /tmp/p.md
|
||||
curl -sk -w "\nPATCH heading: %{http_code}\n" -X PATCH \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
-H "Operation: append" \
|
||||
-H "Target-Type: heading" \
|
||||
-H "Target: Section A" \
|
||||
-H "Content-Type: text/markdown" \
|
||||
--data-binary @/tmp/p.md \
|
||||
"$HOST/vault/scratch/repro.md"
|
||||
|
||||
# 3. GET the heading's content via URL path — expected 200, actual 404
|
||||
curl -sk -w "\nGET heading: %{http_code}\n" \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
"$HOST/vault/scratch/repro.md/heading/Section%20A"
|
||||
|
||||
# 4. CONTROL: PATCH frontmatter — works (HTTP 200)
|
||||
curl -sk -w "\nPATCH frontmatter: %{http_code}\n" -X PATCH \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
-H "Operation: replace" \
|
||||
-H "Target-Type: frontmatter" \
|
||||
-H "Target: type" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '"updated"' \
|
||||
"$HOST/vault/scratch/repro.md"
|
||||
```
|
||||
|
||||
## Actual output
|
||||
|
||||
```
|
||||
PUT: 204
|
||||
|
||||
{"message":"The patch you provided could not be applied to the target content.\ninvalid-target","errorCode":40080}
|
||||
PATCH heading: 400
|
||||
|
||||
{"message":"Not Found","errorCode":40400}
|
||||
GET heading: 404
|
||||
|
||||
PATCH frontmatter: 200
|
||||
```
|
||||
|
||||
## Variations tried (all fail identically with `invalid-target` / 404)
|
||||
|
||||
- Single-word heading (`Target: Section`) and multi-word (`Target: Section A`)
|
||||
- URL-encoded header value (`Target: Section%20A`)
|
||||
- `Operation: append`, `prepend`, and `replace`
|
||||
- Both freshly-PUT files (LF endings) and files originally written by Obsidian
|
||||
- `Target-Type: block` also returns `invalid-target` — possibly the same resolver
|
||||
|
||||
## What I ruled out
|
||||
|
||||
- **CRLF / BOM in source file** — fresh file was written by `curl --data-binary` with LF-only content.
|
||||
- **Spaces in heading text** — single-word headings fail the same way.
|
||||
- **URL encoding of `Target:` header value** — raw and percent-encoded both fail.
|
||||
- **PATCH route generally broken** — `Target-Type: frontmatter` succeeds on the same file.
|
||||
- **Version regression in 4.1.1** — same behavior in 3.6 before upgrading.
|
||||
|
||||
## Environment
|
||||
|
||||
- Obsidian Local REST API: **4.1.1** (also reproduced in 3.6)
|
||||
- Obsidian: <fill in your Obsidian app version>
|
||||
- OS hosting Obsidian: <fill in>
|
||||
- Client: `curl` over HTTPS to `:27124` with `-k` (self-signed cert)
|
||||
- Vault is on local NTFS / ext4 / APFS (fill in)
|
||||
|
||||
## Suspected cause
|
||||
|
||||
The heading resolver appears to be returning "not found" for every valid heading. Since `GET /vault/<path>/heading/<name>` and the `Target-Type: heading` PATCH variant both fail in lockstep (and frontmatter resolution works fine on the same request path), the most likely location is whichever helper enumerates headings within a parsed file's AST — perhaps it's getting an empty list, or matching on a wrong field.
|
||||
|
||||
Happy to bisect or add logging if you can point me at the relevant file.
|
||||
Reference in New Issue
Block a user