{"record":{"id":"e4483ca46305a39a","repo":"denoland/deno","slug":"unsupported-exports-shape-in-deno-json-expected","errorCode":null,"errorMessage":"unsupported 'exports' shape in deno.json: expected a string or object, got {}","messagePattern":"unsupported 'exports' shape in deno\\.json: expected a string or object, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/pack/package_json.rs","lineNumber":180,"sourceCode":"              // omit `types` when no .d.ts was generated\n            } else {\n              rewritten.insert(\n                condition.clone(),\n                json!(format!(\"./{}\", ts_to_js_extension(path))),\n              );\n            }\n          } else {\n            rewritten.insert(condition.clone(), cond_value.clone());\n          }\n        }\n        result.insert(key.clone(), serde_json::Value::Object(rewritten));\n      }\n    }\n\n    return Ok(serde_json::Value::Object(result));\n  }\n\n  deno_core::anyhow::bail!(\n    \"unsupported 'exports' shape in deno.json: expected a string or object, got {}\",\n    exports\n  )\n}\n\nfn extract_main_and_types(\n  exports: &Option<serde_json::Value>,\n  dts_set: &HashSet<String>,\n) -> (Option<String>, Option<String>) {\n  let Some(exports) = exports else {\n    let types = if dts_set.contains(\"mod.js\") {\n      Some(\"./mod.d.ts\".to_string())\n    } else {\n      None\n    };\n    return (Some(\"./mod.js\".to_string()), types);\n  };\n","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/cli/tools/pack/package_json.rs#L162-L198","documentation":"`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.","triggerScenarios":"A deno.json like { \"exports\": [\"./mod.ts\"] } or { \"exports\": 42 } passed to `deno pack`.","commonSituations":"Copy-pasting array-style exports from Node package.json docs; typos wrapping exports in brackets; code generators emitting arrays.","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)"],"exampleFix":"// deno.json before\n\"exports\": [\"./mod.ts\"]\n// after\n\"exports\": \"./mod.ts\"\n// or\n\"exports\": { \".\": \"./mod.ts\", \"./sub\": \"./sub.ts\" }","handlingStrategy":"type-guard","validationCode":"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\");'","typeGuard":"function isValidExports(v: unknown): boolean {\n  return typeof v === \"string\"\n    || (typeof v === \"object\" && v !== null && !Array.isArray(v));\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["pack","exports","config","deno-json"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}