Skip to content

Mime.detect treats truncated multi-byte UTF-8 as text/plain #56183

Open

Description

@smartworldarafath

Description

In \packages/core/src/mime.ts, \isBinary\ uses \decoder.decode(chunk, { stream: true })\ without a final flushing call. If a buffer ends with an incomplete multi-byte UTF-8 sequence (e.g. cut-off \

Activity

  1. opencode-agent commented on Oct 16, 2026

    @opencode-agent
    Contributor

    Thanks for the report. I could reproduce this: on v2.0.31 and on the latest dev (0a03b4b), Mime.detect returns text/plain for [0x61, 0x62, 0xC3] and [0x61, 0xE2, 0x82]. Invalid bytes in the middle of the buffer ([0xC3, 0x41, 0x42]) are correctly reported as application/octet-stream. The script below shows this.

    One thing to consider for #55946: the read tool calls Mime.detect only on the first 256 KiB of a file (FIRST_CHUNK in read-filesystem.ts). That cut can land in the middle of a valid multi-byte character, so { stream: true } may be deliberate there. Always flushing would make some valid UTF-8 files look binary. The fix may need to flush only when the bytes are the whole file, or allow an incomplete character only at the very end of the buffer.

    Reproduction script (mime-truncated.ts)
    // Usage: bun /workspace/repro/mime-truncated.ts <path to packages/core/src/mime.ts>
    const { detect } = await import(process.argv[2] ?? "/workspace/repo/packages/core/src/mime.ts")
    const cases: [string, number[]][] = [
      ["valid 'abc'", [0x61, 0x62, 0x63]],
      ["complete 'é' (C3 A9)", [0x61, 0xc3, 0xa9]],
      ["truncated 2-byte (trailing C3)", [0x61, 0x62, 0xc3]],
      ["truncated 3-byte (trailing E2 82)", [0x61, 0xe2, 0x82]],
      ["invalid mid-buffer (C3 41)", [0xc3, 0x41, 0x42]],
    ]
    for (const [name, b] of cases) console.log(name.padEnd(36), detect(new Uint8Array(b)))

    Run it: bun mime-truncated.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions