[APP-5287] Fix char-boundary panic in workflow AI context menu preview - #14935
[APP-5287] Fix char-boundary panic in workflow AI context menu preview#14935warp-agent-staging[bot] wants to merge 1 commit into
Conversation
WorkflowDataSource::run_query built the workflow description preview by slicing content_preview at a fixed byte offset (197), which panics with "byte index is not a char boundary" whenever a multi-byte UTF-8 character (emoji, CJK, accented char, etc.) straddles that offset. This runs for every workflow on every `@` context menu query, including the zero state, so any user with such a workflow crashes the app. Fix by reusing the existing safe_truncate helper (already used by the sibling notebooks data source and by search_item render paths) which truncates at the nearest valid char boundary instead of a fixed byte index. Fixes APP-5287. Co-Authored-By: Warp Agent <agent@warp.dev>
|
Heads up: this PR and #14933 are two independent fixes for the same panic (APP-5287), produced by two parallel agent runs, and both are attached to the issue. Only one should be merged. They land on the same fix — If the reviewer prefers #14933, the captures here apply to it unchanged and can be copied over. |
|
Closing in favor of #14933, at the reviewer's direction. Both PRs are independent fixes for the same panic (APP-5287), produced by two parallel agent runs, and both make the same core change: replacing the raw The verification work here was not wasted. The recordings and the client log captured on this branch — No code from this branch is lost — #14933 carries the equivalent fix. |
Description
Fixes a production panic reported in Sentry (WARP-CLIENT-BETA-STABLE-87EV):
WorkflowDataSource::run_querypanics withbyte index 197 is not a char boundarywhenever a workflow's content preview has a multi-byte UTF-8 character (emoji, CJK, accented character, etc.) straddling the fixed byte offset 197.WorkflowDataSource::run_querybuilds a ~200-char description preview from the first 3 lines of a workflow's content and truncates it with a fixed byte slice&content_preview[..197]. Rust panics if that index falls inside a multi-byte character instead of on a char boundary.run_queryexecutes when the@context menu's Workflows category is opened or a query is run against it (not merely on the bare@zero state before a category is selected), so any user with a workflow whose preview has a multi-byte character straddling byte 197 crashes the app the moment they open the Workflows category or search within it.Note for anyone reproducing this later:
run_queryreads workflows fromCloudModel(Warp Drive), not the local workflow loaders, so a repro needs the workflow to exist in Warp Drive rather than as a local YAML file on disk.The sibling
notebooks/data_source.rswas already fixed for the same class of bug, and the repo has an existingsafe_truncatehelper (app/src/search/ai_context_menu/mod.rs) built exactly for char-boundary-safe truncation - it's already used by the render-pathsearch_item.rsfiles. This PR reuses that helper inWorkflowDataSource::run_queryinstead of hand-rolling new truncation logic, preserving the existing ~200-char preview +...behavior.notebooks/data_source.rs's existingchar_indices-based truncation was left as-is since its computed endpoint is already a valid char boundary and isn't affected by this bug.I audited the rest of
ai_context_menu/for the same fixed-byte-slice pattern and found no other unsafe instance; the only report was this one spot inworkflows/data_source.rs.Linked Issue
Linear: APP-5287 - https://linear.app/warpdotdev/issue/APP-5287/panic-byte-index-is-not-a-char-boundary-in-workflowdatasourcerun-query
Sentry: https://warpdotdev.sentry.io/issues/7665761472/
Testing
Added
run_query_does_not_panic_on_multibyte_content_previewinapp/src/search/ai_context_menu/workflows/data_source.rs(newdata_source_tests.rs), which builds a workflow whose content is 195 ASCII bytes + a 4-byte emoji (straddling byte 197) + trailing text, inserts it into a mockedCloudModel, and callsWorkflowDataSource::run_query.byte index 197 is not a char boundary; it is inside '🚀' (bytes 195..199).cargo nextest run -p warp -E 'test(run_query_does_not_panic_on_multibyte_content_preview)'- 1 passedcargo nextest run -p warp -E 'test(ai_context_menu::workflows) or test(ai_context_menu::notebooks)'- 6 passed (no regressions in the sibling notebooks data source)cargo fmt -- --check- cleancargo clippy -p warp --all-targets --tests -- -D warnings- cleanAdditionally verified end-to-end with computer use, using a Warp Drive workflow named "Char boundary repro APP-5287" whose content is 241 bytes: 195×
a+🚀at bytes 195-198 +-BOUNDARY-TAIL-PADDING-TO-EXCEED-200-BYTES../script/run(via a computer-use verification agent)Screenshots / Videos
Fixed branch (
oz/app-5287-workflow-preview-panic) - no crash:https://oz.staging.warp.dev/artifacts/019ff146-9d8f-72ee-b741-b9b6f911078f
@→ zero-state menu → Workflows → the repro workflow "Char boundary repro APP-5287" renders with its truncated preview → typingchar boundaryfilters to it → Escape → input still accepts text.master(cd49bd7), same machine, same workflow - crashes:https://oz.staging.warp.dev/artifacts/019ff14c-2725-7821-91a7-b1973b08c5c0
@→ Workflows → the window vanishes instantly and never returns. Client log, verbatim:(fired immediately after
AIContextMenuAction::CategorySelected { category: Workflows })Screenshots:
char boundary: https://oz.staging.warp.dev/artifacts/019ff145-f741-760f-aee1-8d570b642a9emaster- crash: https://oz.staging.warp.dev/artifacts/019ff14c-6751-7e40-88f5-608f448b1f92master- crash: https://oz.staging.warp.dev/artifacts/019ff14d-1444-7c62-88d2-01356c8571cfAgent Mode
Conversation: https://staging.warp.dev/conversation/e2d7d084-0bd9-4afa-a852-950216116378
Run: https://oz.staging.warp.dev/runs/019ff0fd-37ae-7b2c-94ab-2edb6a41b2ce
This PR was generated with Oz.
Co-Authored-By: Warp Agent agent@warp.dev