BoundaryML/baml · error

Only one change event, with full text, is supported for unsa

Error message

Only one change event, with full text, is supported for unsaved files

What it means

set_unsaved_file only supports unsaved (in-memory) documents represented by exactly one content change carrying the full text with no range. Any other shape (multiple incremental changes, ranged edits) is rejected because unsaved buffers are stored as whole-document snapshots.

Source

Thrown at engine/language_server/src/session.rs:356

            session: Arc::new((*self).clone()),
        })
    }

    /// Registers a text document at the provided `url`.
    /// If a document is already open here, it will be overwritten.
    pub(crate) fn open_text_document(&self, document_key: DocumentKey, document: TextDocument) {
        self.index.lock().open_text_document(document_key, document);
    }

    pub(crate) fn set_unsaved_file(
        &mut self,
        document_key: &DocumentKey,
        content_changes: Vec<TextDocumentContentChangeEvent>,
    ) -> anyhow::Result<()> {
        let new_contents: String = match content_changes.as_slice() {
            [event] if event.range.is_none() => event.text.clone(),
            _ => {
                anyhow::bail!(
                    "Only one change event, with full text, is supported for unsaved files"
                )
            }
        };
        for project in self.baml_src_projects.lock().values_mut() {
            let text_document = TextDocument::new(new_contents.clone(), 0);
            project
                .lock()
                .baml_project
                .unsaved_files
                .insert(document_key.clone(), text_document);
        }
        Ok(())
    }

    /// Updates a text document at the associated `key`.
    ///
    /// The document key must point to a text document, or this will throw an error.

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Send unsaved-file content as a single full-text change event (range omitted)
  2. If your client uses incremental sync, aggregate changes into full text before notifying for untitled files
  3. Save the file so it becomes a regular workspace document handled by the normal path
  4. Update the client integration to force full sync (TextDocumentSyncKind.Full) for unsaved buffers

Example fix

// before: ranged edit for unsaved doc
changes: [{ range: {start:{line:0,character:0},end:{line:0,character:3}}, text: "foo" }]
// after: full-text single event
changes: [{ text: fullBufferContents }]
Defensive patterns

Strategy: validation

Validate before calling

if (isUnsaved(uri) && !(contentChanges.length === 1 && contentChanges[0].range === undefined)) {
  contentChanges = [{ text: currentBufferText }];
}

Type guard

function isFullTextSync(changes: unknown[]): boolean { return changes.length === 1 && (changes[0] as any).range === undefined; }

Try / catch

try { await sendUnsavedChange(uri, changes); } catch (e) { if (String(e).includes('full text')) await sendUnsavedChange(uri, [{ text: bufferContents }]); else throw e; }

Prevention

When it happens

Trigger: Client sends didChange for an unsaved/untitled file with multiple TextDocumentContentChangeEvent entries, or a single ranged (incremental) change instead of one full-text change.

Common situations: Typing in an untitled VS Code buffer (incremental edits); editor plugins that send incremental diffs for virtual documents; client sync modes (incremental) mismatched with the server's expectation for unsaved files.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/30923cfe528ad569. Report an issue: GitHub.