From 630b7ad418c5a7d39a5166277c99754b3d56dd66 Mon Sep 17 00:00:00 2001 From: Nicolas Le Cam Date: Wed, 2 Sep 2026 17:47:20 +0200 Subject: [PATCH] fix(prisma): stop migrate status panicking on a trailing migration id `filter_migrate_status` looked for whitespace after the `202...` id and fell back to a hardcoded 20 bytes when there was none -- so an id that runs to the end of the line slices past it: Migration could not be applied at 2024-01-01T12:00:00 len 53, pos 34, end 20 -> line[34..54] -> end byte index 54 is out of bounds Release builds set `panic = "abort"`, so `rtk prisma migrate status` dies and the user loses the command output entirely -- the one thing a filter must never do. A multibyte character straddling that offset panics the same way, on the char boundary instead. The fallback is the rest of the line, which is what the sibling `filter_migrate_dev` has always used 70 lines above. Co-Authored-By: Claude Opus 5 --- src/cmds/js/prisma_cmd.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/cmds/js/prisma_cmd.rs b/src/cmds/js/prisma_cmd.rs index 3deef1c6f9..35593348f8 100644 --- a/src/cmds/js/prisma_cmd.rs +++ b/src/cmds/js/prisma_cmd.rs @@ -316,7 +316,9 @@ fn filter_migrate_status(output: &str) -> String { applied_count += 1; if latest_migration.is_empty() && line.contains("202") { if let Some(pos) = line.find("202") { - let end = line[pos..].find(|c: char| c.is_whitespace()).unwrap_or(20); + let end = line[pos..] + .find(|c: char| c.is_whitespace()) + .unwrap_or(line.len() - pos); latest_migration = line[pos..pos + end].to_string(); } } @@ -462,6 +464,21 @@ import { PrismaClient } from '@prisma/client' assert!(!result.contains("Start by importing")); } + #[test] + fn test_filter_migrate_status_reads_a_timestamp_at_end_of_line() { + // The migration id ran to the end of the line, so there was no whitespace to find and + // the hardcoded fallback of 20 sliced past it -- a panic, which aborts in release and + // takes the user's whole command output with it. + let output = "Migration could not be applied at 2024-01-01T12:00:00"; + let result = filter_migrate_status(output); + assert!(result.contains("2024-01-01T12:00:00"), "{result}"); + + // A multibyte character after the id must not split mid-char either. + let output = "1 migration applied 20240101_café"; + let result = filter_migrate_status(output); + assert!(result.contains("20240101_café"), "{result}"); + } + #[test] fn test_filter_migrate_dev() { let output = r#"