Skip to content

edit: find/replace on a nonexistent document reports "Text not found in document"; frontmatter patch and append silently create it #1719

Description

@Acroaticum

Summary

Three MCP write paths treat a document path that does not exist as a brand-new document instead of refusing.

For an agent the practical failure is that edit blames the find string for what is actually a wrong path, so the agent re-reads the file from disk, sees the text plainly there, and retries forever. Meanwhile write ... position: "append" against the same wrong path reports success and creates a phantom file elsewhere in the tree.

Environment

  • MCP server: npx -y @inkeep/open-knowledge@latest mcp0.75.0 (this is the stdio registration ok init writes)
  • Project server: 0.68.6 (CLI on PATH), started with ok start --only server --idle-shutdown off
  • macOS 27.0.0 arm64, content.dir: ., client is Claude Code

The version split is what the default registration produces: the MCP entry pins @latest while the CLI on PATH is whatever the package manager installed. I could not retest with matched versions — other live sessions held collaboration clients, and ok stop correctly refused to kill them.

Reproduction

1. Body find/replace against a path with no document

edit({ cwd, document: { path: "wiki/zz-probe", find: "a word that is definitely here", replace: "replaced" } })
→ Error: Text not found in document.
$ ls wiki/zz-probe.md
ls: wiki/zz-probe.md: No such file or directory

Nothing was created, but the error names the text, not the missing document. It is byte-identical to the error you get when the document exists and the find string is stale.

2. Frontmatter patch against the same nonexistent path

edit({ cwd, document: { path: "wiki/zz-probe", frontmatter: { title: "probe" } } })
→ Frontmatter patched (1 set).
$ cat wiki/zz-probe.md
---
title: probe
---

A new file, with nothing in the response saying this was a create rather than a patch.

3. Append against a nonexistent path

write({ cwd, document: { path: "wiki/zz-probe-2", content: "appended line\n", position: "append" } })
→ Written successfully (append).

New file created. The only signal is an advisory orphan hint ("This doc has no backlinks yet"), which reads as routine.

4. Control — the same find/replace on a document that does exist

edit({ cwd, document: { path: "wiki/zz-probe-2", find: "appended line", replace: "appended line (control passed)" } })
→ Edit applied successfully.

So find/replace itself is fine. The defect is entirely in how a missing document is reported.

What this cost in practice

Our content root is the repository root; a knowledge bundle lives under .okf/. Several agents addressed documents bundle-relative — system/ways-of-working/operations — instead of .okf/system/ways-of-working/operations.

The dotted path is correctly refused (docName path segments must not start with "."), which is clear. The un-prefixed path is the problem: it silently resolves to a new document at the repository root. Result:

  • every body find/replace returned "Text not found in document", so the agents concluded the document's content had drifted and kept re-reading it from disk, where the text was plainly present;
  • the documented append workaround then reported success and wrote 6,945 bytes into a phantom system/ways-of-working/operations.md at the repo root;
  • nobody noticed for a day, and 2,119 bytes of that content never reached the real document.

Suggested fix

  1. edit with find/replace against a path that has no document should fail with a distinct error — e.g. No document at "<path>" — rather than Text not found in document. Today the two are indistinguishable and send the agent to debug the wrong thing.
  2. A call that creates a document as a side effect (edit + frontmatter, write + position: append/prepend) should say so in the response text — something like Created new document <path> — so an agent aiming at an existing document can detect the miss on the first call.
  3. Optionally: when a nonexistent path's trailing segments match an existing document elsewhere in the tree, suggest it.

Happy to test a fix against the same setup.

Activity

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions