Repository navigation
Description
Summary
Copying a rendered chat image whose local path contains a space produces plain Markdown that no longer represents an image. The copied text should keep a usable image reference when pasted into Markdown. I reproduced the copy output with the checkout's helper and verified that the checkout's Markdown parser recognizes the original image but no image in the copied text.
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/web
Steps to reproduce
- At commit c00a373 with dependencies installed, save the script below as
repro.shand runsh repro.sh /path/to/t3code. - The script parses a valid image with a spaced destination, passes its parsed path to the checkout's
markdownImageCopy, and parses the copied result; it also checks an image path without a space as a setup control.
The focused run reproduced the failure once in one run. The source trace under Actual behavior establishes how the same copy value reaches the browser clipboard; an interactive browser copy was not run.
The script requires Node and the checkout's installed unified and remark-parse dependencies. It reads the helper from the checkout, creates and removes its input under a temporary directory, and leaves the checkout unchanged. Exit 0 means the copied text retains the image, exit 1 means the defect was reproduced, and exit 2 means the input or control could not establish the result.
Reproduction script: repro.sh
#!/bin/sh
set -u
repo=${1:-}
if [ -z "$repo" ] || [ ! -f "$repo/apps/web/src/components/chat/ChatMarkdownMedia.tsx" ]; then
printf '%s\n' 'RESULT: inconclusive'
exit 2
fi
repo=$(cd "$repo" && pwd)
printf 'node %s\n' "$(node --version)"
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT HUP INT TERM
mkdir -p "$scratch/home" "$scratch/tmp" "$scratch/state"
export HOME="$scratch/home" TMPDIR="$scratch/tmp" T3CODE_HOME="$scratch/state"
awk '/^export function markdownImageCopy\(/,/^}/' "$repo/apps/web/src/components/chat/ChatMarkdownMedia.tsx" | sed 's/^export //' > "$scratch/repro.ts"
if ! rg -q '^function markdownImageCopy\(' "$scratch/repro.ts"; then
printf '%s\n' 'RESULT: inconclusive'
exit 2
fi
cat >> "$scratch/repro.ts" <<'TS'
import { createRequire } from "node:module";
const require = createRequire(`${process.argv[2]}/packages/shared/package.json`);
const { unified } = require("unified");
const remarkParse = require("remark-parse").default;
const images = (markdown: string) => {
const root = unified().use(remarkParse).parse(markdown);
return root.children.flatMap((block: any) => block.children ?? []).filter((node: any) => node.type === "image");
};
const source = "";
const original = images(source);
const control = markdownImageCopy("Shot", "/work/shot.png", undefined);
const copied = markdownImageCopy("Shot", original[0]?.url ?? "", undefined);
const controlImages = images(control);
const copiedImages = images(copied);
console.log(`source image count: ${original.length}`);
console.log(`control copy: ${control}`);
console.log(`copied: ${copied}`);
console.log(`copied image count: ${copiedImages.length}`);
if (original.length !== 1 || original[0].url !== "/work/my shot.png" ||
controlImages.length !== 1 || controlImages[0].url !== "/work/shot.png") {
console.log("RESULT: inconclusive");
process.exit(2);
}
if (copiedImages.length === 1 && copiedImages[0].url === original[0].url) {
console.log("RESULT: expected behavior");
process.exit(0);
}
console.log("RESULT: defect reproduced");
process.exit(1);
TS
node "$scratch/repro.ts" "$repo"Expected behavior
Copying an image from rendered chat should keep a usable image reference in the plain Markdown, including when its destination has a space. The renderer already accepts the angle-bracketed form in a browser test (apps/web/src/components/ChatMarkdown.browser.test.tsx#L206-L220), and T3 Code writes angle-bracketed image embeds for saved images (packages/shared/src/generatedImageMarkdown.ts#L11-L21).
Actual behavior
When the chat renders , its image copy value becomes . The latter contains no image node when parsed as Markdown. The supported copy action uses that value as the clipboard's plain text: the image component receives copyMarkdown, the serializer reads data-markdown-copy, and the chat's onCopy handler writes the serialized payload (apps/web/src/components/ChatMarkdown.tsx#L1474-L1485, apps/web/src/components/chat/ChatMarkdownMedia.tsx#L200-L209, apps/web/src/markdown-clipboard.ts#L223-L232, apps/web/src/components/ChatMarkdown.tsx#L675-L682, apps/web/src/components/ChatMarkdown.tsx#L1867-L1871).
Impact and scope
Impact: P2 - copying these images silently produces text that loses the image when pasted into a Markdown editor or chat.
This affects the web chat's plain-text selection copy for image paths containing spaces. The same client is used in the desktop wrapper. A user can repair the pasted destination by hand with angle brackets or attach the image again. The script establishes the failure for a POSIX local path; other path forms and the rich HTML clipboard flavor were not tested.
Earliest failure stage
Output or presentation.
Analysis or suspected cause
The helper emits the bare destination (apps/web/src/components/chat/ChatMarkdownMedia.tsx#L36-L41); normalization removes angle brackets before it is called (packages/shared/src/markdownLinks.ts#L227-L230). The actual parser run shows the copied text no longer has an image node.
Additional context
Current main still uses the same markdownImageCopy return expression and ChatMarkdown call; checked through the GitHub API after reviewing recent file commits.
Impact
Minor bug or occasional failure
Version or commit
main @ c00a373
Environment
Node v26.12.1 on macOS 27.2.0 arm64. The reproduction uses the checkout's installed remark-parse 11.0.0 and unified 11.0.5.
Logs or stack traces
node v26.12.1
source image count: 1
control copy: 
copied: 
copied image count: 0
RESULT: defect reproducedScreenshots, recordings, or supporting files
No response
Workaround
A user can repair the pasted destination by hand with angle brackets or attach the image again.
References
- Media embeds don't render when the file path contains a space (agents aren't told to wrap paths in <…>) #26685 — reports unwrapped spaced paths in agent output failing to render; this report starts with a correctly rendered image and concerns its copied Markdown.
- fix(web): images and file links render when a Windows path has a space #27970 — changes parsing of unwrapped Windows paths; its described scope does not change the copied Markdown.
- Markdown image with a space in the local path renders as raw text #34386 — closed as a duplicate of the rendering report; it does not cover copying a correctly rendered image.
Activity