denoland / denoland/deno

deno publish rejects ("import attribute type of text is unsupported") even though it is runtime-stable and --dry-run accepts it

Open
#35,546 2 comments 0 reactions 0 assignees View on GitHub
publish
Dominant language
Rust
Stars
108k
Forks
6.4k
Avg merge
2d 20h
Merged PRs (30d)
58

Description

### What happened

`deno publish` fails to build the publish module graph for any package that imports an asset with a `with { type: "text" }` import attribute, erroring with:

```
The import attribute type of "text" is unsupported.
```

This happens **even though**:

- `with { type: "text" }` imports are runtime-stable as of Deno 2.8 (#34238), and
- `deno publish --dry-run` accepts the exact same packages and reports success.

So the only place the rejection surfaces is the **real** (authenticated) `deno publish` tarball graph build — which makes it invisible to `--dry-run` and to any unauthenticated preflight.

### Reproduction

**A. `deno publish --dry-run` accepts a text import (local, Deno 2.9.0):**

`deno.json`
```json
{
"name": "@example/text-import-repro",
"version": "0.0.1",
"license": "MIT",
"exports": "./mod.ts"
}
```

`asset.txt`
```
hello from a text asset
```

`mod.ts`
```ts
import asset from "./asset.txt" with { type: "text" };
export const assetText: string = asset;
```

```console
$ deno --version
deno 2.9.0 (stable, release, x86_64-pc-windows-msvc)

$ deno publish --dry-run --allow-dirty
Checking for slow types in the public API...
Simulating publish of @example/text-import-repro@0.0.1 with files:
.../asset.txt (24B)
.../deno.json (109B)
.../mod.ts (94B)
Success Dry run complete
```

`--dry-run` is green and even lists `asset.txt` in the publish file set.

**B. The real authenticated `deno publish` rejects the identical imports (GitHub Actions, Deno 2.9.0):**

Publishing a 31-member workspace where two members import assets `with { type: "text" }` fails at the **Publish** step (after the green dry-run in the same job):

```
error: Failed to publish 2 packages:
* Failed to publish @netscript/fresh-ui@0.0.1-alpha.6: failed to build module graph: The import attribute type of "text" is unsupported.
Specifier: file:///registry/lib/toast.ts
* Failed to publish @netscript/plugin@0.0.1-alpha.6: failed to build module graph: The import attribute type of "text" is unsupported.
Specifier: file:///src/templates/skeleton/README.md.template
Warning Skipped publishing 6 package(s) that depended on a package that failed to publish
error: Uncaught (in promise) Error: Publish failed (deno publish exit 1).
```

Public CI run (logs viewable): https://github.com/rickylabs/netscript/actions/runs/28259940478

Reproduced twice on separate releases (same error, same two members).

### Why this is painful

1. **`--dry-run` is not a faithful preview.** It accepts text imports that the real publish then rejects. A green dry-run in the same CI job gives a false all-clear.
2. **Partial workspace publish.** In a workspace publish, the two rejected members caused 6 dependents to be skipped — 23/31 members published, leaving the workspace at mixed versions until a follow-up release. There's no atomic rollback.
3. **The failure is post-auth.** The graph rejection happens after the bearer token is validated, so it cannot be caught by an unauthenticated `deno publish` preflight (an invalid token short-circuits before the per-member graph build). Combined with (1), there is effectively no way to detect this before a real publish.

### Expected

Given that text imports are runtime-stable and pass `deno check` / `deno publish --dry-run`, the real `deno publish` should either:

- publish them successfully (enable the same text-import support in the publish tarball graph builder), or
- at minimum, **fail in `--dry-run` too**, so the incompatibility is caught before any upload and before a workspace is left half-published.

### Workaround (for anyone hitting this)

Inline the asset as a plain string constant in a generated `.ts` module (`const x = "...JSON.stringify'd content...";`) instead of using an import attribute. With no import attribute, the publish graph has nothing to reject. This is the deno-embedder-style approach; it publishes cleanly but loses the ergonomics of `with { type: "text" }`.

### Environment

- Deno 2.9.0 (stable) — reproduced on both `x86_64-pc-windows-msvc` (dry-run accepts) and GitHub Actions `ubuntu` via `setup-deno@v2` (real publish rejects).
- Related: text-import runtime stabilization #34238; the `unstable-raw-import` publish *lint* was addressed in 2.9 — but this is the distinct **graph-build** stage, not the lint.

Contributor guide

Open the contributing guide

Research direction

Start with the deno publish and deno publish --dry-run paths, using the provided deno.json, mod.ts, and asset.txt reproduction to compare their module-graph behavior. Reproduce the authenticated failure and confirm that text imports with { type: "text" } are handled consistently; done means real publish succeeds or dry-run reports the same rejection.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, typescript
Domain
cli, release
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.