{"record":{"id":"eaa7267d71c6b2b9","repo":"biomejs/biome","slug":"empty-file-eaa726","errorCode":null,"errorMessage":"empty file","messagePattern":"empty file","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/biome_service/src/file_handlers/javascript.rs","lineNumber":1673,"sourceCode":"    settings: &SettingsWithEditor,\n    offset: TextSize,\n    workspace_db: WorkspaceDb,\n) -> Result<Printed, WorkspaceError> {\n    let options = resolve_format_options(path, document_file_source, settings, &workspace_db);\n    debug!(\"{:?}\", &options);\n    let tree = parse.syntax(&workspace_db);\n\n    let range = tree.text_range_with_trivia();\n    if offset < range.start() || offset > range.end() {\n        return Err(WorkspaceError::FormatError(FormatError::RangeError {\n            input: TextRange::at(offset, TextSize::from(0)),\n            tree: range,\n        }));\n    }\n\n    let token = match tree.token_at_offset(offset) {\n        // File is empty, do nothing\n        TokenAtOffset::None => panic!(\"empty file\"),\n        TokenAtOffset::Single(token) => token,\n        // The cursor should be right after the closing character that was just typed,\n        // select the previous token as the correct one\n        TokenAtOffset::Between(token, _) => token,\n    };\n\n    if token.text_trimmed_range().end() != offset {\n        return Ok(format_on_type_noop(offset));\n    }\n\n    if !matches_on_type_char(token.text_trimmed()) {\n        return Ok(format_on_type_noop(offset));\n    }\n\n    let root_node = match token.parent() {\n        Some(node) => node,\n        None => panic!(\"found a token with no parent\"),\n    };","sourceCodeStart":1655,"sourceCodeEnd":1691,"githubUrl":"https://github.com/biomejs/biome/blob/0fca643d22845c28e0e0b7375013155e3f80717f/crates/biome_service/src/file_handlers/javascript.rs#L1655-L1691","documentation":"Panic in the JavaScript format-on-type handler (javascript.rs:1638). For a textDocument/onTypeFormatted request, Biome resolves the token under the cursor with tree.token_at_offset(offset); TokenAtOffset::None means the parsed tree contains no tokens, i.e. the document is empty. Despite the 'File is empty, do nothing' comment, the arm panics, so on-type formatting an empty JS/TS/JSX document crashes this path.","triggerScenarios":"An LSP client sends onTypeFormatted for a zero-length .js/.ts/.jsx file: offset 0 passes the range guard over tree range 0..0, token_at_offset(0) returns None, and the panic fires. Any non-empty file returns at least a token and avoids this arm.","commonSituations":"The most-hit variant of this bug since JS files dominate Biome usage: editors firing on-type format on empty buffers (new untitled files, cleared documents), aggressive format-on-key plugins, or LSP test harnesses.","solutions":["Update Biome - check release notes for a fix and report at https://github.com/biomejs/biome/issues if still present","Client-side guard: only send textDocument/onTypeFormatted when document.getText().length > 0","In a fork: TokenAtOffset::None => return Ok(format_on_type_noop(offset))"],"exampleFix":"// before\nTokenAtOffset::None => panic!(\"empty file\"),\n\n// after\nTokenAtOffset::None => return Ok(format_on_type_noop(offset)),","handlingStrategy":"validation","validationCode":"// LSP client (TypeScript) - skip on-type formatting for empty JS/TS files\nif (document.getText().length === 0) return; // avoid the server-side panic path","typeGuard":"const isEmptyDocument = (document: TextDocument): boolean =>\n  document.getText().length === 0;","tryCatchPattern":null,"preventionTips":["Guard every textDocument/onTypeFormatted send with a non-empty check - empty buffers are common (untitled files, full deletions)","Do not register onTypeFormatting until the first content change of a session","Keep the Biome extension/server updated; this panic family affects all language handlers"],"tags":["javascript","lsp","format-on-type","panic","empty-file"],"backgroundTag":"format-on-type-empty-document","analyzedSha":"0fca643d22845c28e0e0b7375013155e3f80717f","analyzedAt":"2026-08-20T00:25:09.682Z","contentChangedAt":"2026-08-20T00:25:09.682Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}