astral-sh/ruff · error

Notebook document path does not point to a notebook document

Error message

Notebook document path does not point to a notebook document

What it means

On notebookDocument/didChange, the notebook key resolved to a document that is not a notebook (as_notebook_mut() returned None), so update_notebook_document bails (index.rs:76). The index stores text and notebook documents under distinct key namespaces; a mismatch means the client used the notebook API for a plain text document.

Source

Thrown at crates/ty_server/src/session/index.rs:76

    #[expect(dead_code)]
    fn notebook_document_keys(&self) -> impl Iterator<Item = &DocumentKey> + '_ {
        self.documents
            .iter()
            .filter(|(_, doc)| doc.as_notebook().is_some())
            .map(|(key, _)| key)
    }

    pub(super) fn update_notebook_document(
        &mut self,
        notebook_key: &DocumentKey,
        cells: Option<lsp_types::NotebookDocumentCellChanges>,
        metadata: Option<serde_json::Map<String, serde_json::Value>>,
        new_version: DocumentVersion,
        encoding: PositionEncoding,
    ) -> crate::Result<()> {
        let document = self.document_mut(notebook_key)?;
        let Some(notebook) = document.as_notebook_mut() else {
            anyhow::bail!("Notebook document path does not point to a notebook document");
        };

        let (structure, data, text_content) = cells
            .map(|cells| {
                let lsp_types::NotebookDocumentCellChanges {
                    structure,
                    data,
                    text_content,
                } = cells;
                (structure, data, text_content)
            })
            .unwrap_or_default();

        let (array, did_open, did_close) = structure
            .map(|structure| {
                let lsp_types::NotebookDocumentCellChangeStructure {
                    array,
                    did_open,

View on GitHub (pinned to 672bb4edf0)

Solutions

  1. Always open via didOpenNotebookDocument before sending notebook didChange
  2. Match the exact notebookDocument.uri used in the didOpen
  3. After a desync, reopen the notebook file to re-register it as a notebook

Example fix

// before
notify('notebookDocument/didChange', { notebookDocument: { uri, version }, ... });

// after
notify('notebookDocument/didOpen', { notebookDocument: { uri, version, notebookType, cells } });
notify('notebookDocument/didChange', { notebookDocument: { uri, version }, change });
Defensive patterns

Strategy: type-guard

Validate before calling

// TS: only send notebook didChange for URIs opened as notebooks
const openNotebooks = new Set<string>();
client.onNotification('notebookDocument/didOpen', () => {}); // track via your own didOpen calls
function changeNotebook(uri: string, change: unknown) {
  if (!openNotebooks.has(uri)) return; // never opened -> would hit the bail
  notify('notebookDocument/didChange', { notebookDocument: { uri, version: next() }, change });
}

Type guard

const isOpenNotebook = (uri: string): boolean => openNotebooks.has(uri);

Prevention

When it happens

Trigger: Sending notebookDocument/didChange for a URI the server stored as a text document — e.g. never sending didOpenNotebookDocument first, or addressing a regular .py file with the notebook notification.

Common situations: Clients skipping notebook didOpen, restart races where the editor replays didChange for a notebook the server never saw, or a mismatched pair of client/server notebook-protocol versions.

Related errors


AI-assisted analysis of astral-sh/ruff@672bb4edf0 (2026-08-16). Data as JSON: /api/errors/1863cb449d9d0590. Report an issue: GitHub.