denoland/deno · error
unsupported 'exports' shape in deno.json: expected a string
Error message
unsupported 'exports' shape in deno.json: expected a string or object, got {} What it means
`deno pack` converts deno.json's "exports" field into package.json exports. Only two shapes are accepted: a plain string ("./mod.ts") or an object mapping keys/conditions to values. Any other JSON type (array, number, boolean) is rejected with this message showing the offending value.
Source
Thrown at cli/tools/pack/package_json.rs:180
// omit `types` when no .d.ts was generated
} else {
rewritten.insert(
condition.clone(),
json!(format!("./{}", ts_to_js_extension(path))),
);
}
} else {
rewritten.insert(condition.clone(), cond_value.clone());
}
}
result.insert(key.clone(), serde_json::Value::Object(rewritten));
}
}
return Ok(serde_json::Value::Object(result));
}
deno_core::anyhow::bail!(
"unsupported 'exports' shape in deno.json: expected a string or object, got {}",
exports
)
}
fn extract_main_and_types(
exports: &Option<serde_json::Value>,
dts_set: &HashSet<String>,
) -> (Option<String>, Option<String>) {
let Some(exports) = exports else {
let types = if dts_set.contains("mod.js") {
Some("./mod.d.ts".to_string())
} else {
None
};
return (Some("./mod.js".to_string()), types);
};
View on GitHub (pinned to 89f33cbef2)
Solutions
- Change "exports" to a string or object form
- For multiple entries use the object form keyed by subpath (".", "./sub", ...)
- Validate the config shape before packing (see type guard below)
Example fix
// deno.json before
"exports": ["./mod.ts"]
// after
"exports": "./mod.ts"
// or
"exports": { ".": "./mod.ts", "./sub": "./sub.ts" } Defensive patterns
Strategy: type-guard
Validate before calling
deno eval 'const e = JSON.parse(Deno.readTextSync("deno.json")).exports; if (e !== undefined && typeof e !== "string" && (typeof e !== "object" || Array.isArray(e))) throw new Error("exports must be a string or object");' Type guard
function isValidExports(v: unknown): boolean {
return typeof v === "string"
|| (typeof v === "object" && v !== null && !Array.isArray(v));
} Prevention
- Use the object form with a "." key as the canonical multi-entry exports shape
- Enable deno.json schema validation in editors to catch shape mistakes at edit time
When it happens
Trigger: A deno.json like { "exports": ["./mod.ts"] } or { "exports": 42 } passed to `deno pack`.
Common situations: Copy-pasting array-style exports from Node package.json docs; typos wrapping exports in brackets; code generators emitting arrays.
Related errors
- Missing name
- Missing name in config
- refusing to write tarball with unsafe name derived from pack
- A deno.json file could not be found or created
- Could not load or create deno.json
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/e4483ca46305a39a.
Report an issue: GitHub.