Skip to content

fix: unexpected 'rm-filename' http header 400 error (add .docSchema extension when fetching document index in Mirror - fixes issue #62)#63

Merged
ddvk merged 2 commits into
ddvk:masterfrom
marcobarcelos:fix/blobdoc-missing-docschema-ext
May 20, 2026
Merged

fix: unexpected 'rm-filename' http header 400 error (add .docSchema extension when fetching document index in Mirror - fixes issue #62)#63
ddvk merged 2 commits into
ddvk:masterfrom
marcobarcelos:fix/blobdoc-missing-docschema-ext

Conversation

@marcobarcelos

@marcobarcelos marcobarcelos commented May 18, 2026

Copy link
Copy Markdown

All operations that build the document tree fail with HTTP 400 and the message {"message":"unexpected 'rm-filename' http header"} since reMarkable updated their API.

The root cause: BlobDoc.Mirror() was fetching each document's index blob with rm-filename: <uuid>, but the API now requires rm-filename: <uuid>.docSchema.

One-line change - use addExt(e.DocumentID, archive.DocSchemaExt) when calling GetReader, consistent with how uploads already work throughout apictx.go.

Verified with rmapi ls and rmapi put against the live reMarkable cloud API (May 2026).

Fixes #62

  BlobDoc.Mirror() was passing only the UUID as rm-filename header when fetching the document index blob. The API requires UUID.docSchema, consistent with how uploads already use addExt(doc.DocumentID, DocSchemaExt). Fixes status 400 on document blob fetches

@bgeisel1 bgeisel1 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @marcobarcelos! I'd recommend also applying the fix I've attached below as a diff. The blobdoc.go fixes the state where you already have the cache. But you have to also patch tree.go to catch cold start with no cache. New installs will go down this second path.

Hope that helps! With this change, I fully agree with this fix. I verified with blob GETs, put-to-folder works, etc.

diff --git a/api/sync15/tree.go b/api/sync15/tree.go
index 3e58c30..77cf190 100644
--- a/api/sync15/tree.go
+++ b/api/sync15/tree.go
@@ -374,7 +374,7 @@ func BuildTree(provider RemoteStorage) (*HashTree, error) {
        tree.SchemaVersion = schema
 
        for _, e := range entries {
-               f, err := provider.GetReader(e.Hash, e.DocumentID)
+               f, err := provider.GetReader(e.Hash, addExt(e.DocumentID, archive.DocSchemaExt))
                if err != nil {
                        return nil, fmt.Errorf("failed to read blob %s: %w", e.DocumentID, err)
                }

@marcobarcelos marcobarcelos changed the title fix: add .docSchema extension when fetching document index in Mirror to fix error 400 (unexpected 'rm-filename' http header error) fix: add .docSchema extension when fetching document index in Mirror to fix error 400 (unexpected 'rm-filename' http header error) Fixes #62 May 18, 2026
@marcobarcelos marcobarcelos changed the title fix: add .docSchema extension when fetching document index in Mirror to fix error 400 (unexpected 'rm-filename' http header error) Fixes #62 fix: add .docSchema extension when fetching document index in Mirror to fix error 400 (unexpected 'rm-filename' http header error - fixes #62) May 18, 2026
@Azeirah

Azeirah commented May 18, 2026

Copy link
Copy Markdown

Hey @marcobarcelos! I'd recommend also applying the fix I've attached below as a diff. The blobdoc.go fixes the state where you already have the cache. But you have to also patch tree.go to catch cold start with no cache. New installs will go down this second path.

Hope that helps! With this change, I fully agree with this fix. I verified with blob GETs, put-to-folder works, etc.

diff --git a/api/sync15/tree.go b/api/sync15/tree.go
index 3e58c30..77cf190 100644
--- a/api/sync15/tree.go
+++ b/api/sync15/tree.go
@@ -374,7 +374,7 @@ func BuildTree(provider RemoteStorage) (*HashTree, error) {
        tree.SchemaVersion = schema
 
        for _, e := range entries {
-               f, err := provider.GetReader(e.Hash, e.DocumentID)
+               f, err := provider.GetReader(e.Hash, addExt(e.DocumentID, archive.DocSchemaExt))
                if err != nil {
                        return nil, fmt.Errorf("failed to read blob %s: %w", e.DocumentID, err)
                }

To verify this you just have to reset the cache, right?

@marcobarcelos marcobarcelos requested a review from bgeisel1 May 18, 2026 21:16
@marcobarcelos

Copy link
Copy Markdown
Author

Thanks @bgeisel1 , well observed. I applied the fix for cold start aswell (no cache).

@marcobarcelos marcobarcelos changed the title fix: add .docSchema extension when fetching document index in Mirror to fix error 400 (unexpected 'rm-filename' http header error - fixes #62) fix: unexpected 'rm-filename' http header 400 error (add .docSchema extension when fetching document index in Mirror - fixes issue #62) May 18, 2026

@bgeisel1 bgeisel1 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! This random guy on the internet says we should merge it! :-)

@marcobarcelos

Copy link
Copy Markdown
Author

LGTM! This random guy on the internet says we should merge it! :-)

Haha thanks. Just waiting for maintainer approval.

1 workflow awaiting approval
This workflow requires approval from a maintainer.

@bgeisel1

Copy link
Copy Markdown

Hey @marcobarcelos! I'd recommend also applying the fix I've attached below as a diff. The blobdoc.go fixes the state where you already have the cache. But you have to also patch tree.go to catch cold start with no cache. New installs will go down this second path.
Hope that helps! With this change, I fully agree with this fix. I verified with blob GETs, put-to-folder works, etc.

diff --git a/api/sync15/tree.go b/api/sync15/tree.go
index 3e58c30..77cf190 100644
--- a/api/sync15/tree.go
+++ b/api/sync15/tree.go
@@ -374,7 +374,7 @@ func BuildTree(provider RemoteStorage) (*HashTree, error) {
        tree.SchemaVersion = schema
 
        for _, e := range entries {
-               f, err := provider.GetReader(e.Hash, e.DocumentID)
+               f, err := provider.GetReader(e.Hash, addExt(e.DocumentID, archive.DocSchemaExt))
                if err != nil {
                        return nil, fmt.Errorf("failed to read blob %s: %w", e.DocumentID, err)
                }

To verify this you just have to reset the cache, right?

Actually, @Azeirah , it looks like I misread -- I dug in a little more and I think this is dead code. Maybe from starting to build an API to use this as a library or something a while ago. If it ever gets wired in, it'll need this fix.

That being said, we could probably open another issue to delete it, but I don't have enough intent-understanding of the code to suggest it. I probably just diligently suggested fixing some dead code. :-(

Thanks for being willing to test it!

@gknayzeh

Copy link
Copy Markdown

Confirming this fixes the cold-pair / fresh-device path on macOS arm64, May 2026. Specifically the BuildTree change in a0d0799 — that was the failure mode I was hitting after a fresh rmapi pair on a new machine: failed to mirror was not ok: request failed with status 400 immediately after the one-time code was accepted, with no rmapi.conf persisted because the first mirror never completed.

Trace evidence lined up with the diagnosis: GET /sync/v3/files/<root-hash> was succeeding with rm-filename: root.docSchema, but the subsequent index-blob fetches in BuildTree were going out with bare UUIDs and the server was rejecting them. Wrapping with addExt(..., archive.DocSchemaExt) at both call sites resolves it cleanly — first mirror completes, config persists, ls and put work, and <leader>nR from my Neovim bridge now round-trips to the tablet.

Would love to see this merged so I can point my install back at an upstream release rather than maintaining a local build.

@marcobarcelos

Copy link
Copy Markdown
Author

Confirming this fixes the cold-pair / fresh-device path on macOS arm64, May 2026. Specifically the BuildTree change in a0d0799 — that was the failure mode I was hitting after a fresh rmapi pair on a new machine: failed to mirror was not ok: request failed with status 400 immediately after the one-time code was accepted, with no rmapi.conf persisted because the first mirror never completed.

Trace evidence lined up with the diagnosis: GET /sync/v3/files/<root-hash> was succeeding with rm-filename: root.docSchema, but the subsequent index-blob fetches in BuildTree were going out with bare UUIDs and the server was rejecting them. Wrapping with addExt(..., archive.DocSchemaExt) at both call sites resolves it cleanly — first mirror completes, config persists, ls and put work, and <leader>nR from my Neovim bridge now round-trips to the tablet.

Would love to see this merged so I can point my install back at an upstream release rather than maintaining a local build.

Thanks for confirming! Regarding the merge, I’m currently waiting for approval from adm.

@ddvk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Any operations fail with status 400

5 participants