# Troubleshooting dsh-artifacts: templates, listing, media and agent tools
Checked on: DSH 0.1.5-rc.1, 0.2.1-rc.5 and 0.2.1, plugin 2.2.0.
**Start here.** Every failed tool result carries a `code`; look it up in [ERRORS.md](ERRORS.md). Collect the
facts in section 0 first: they are read-only and safe.
## Quick index
| # | Symptom (what you see) | Most likely cause | Jump |
|---|---|---|---|
| 1 | No `artifact_templates` tool in the agent's tool list | dsh web not restarted after installing or updating the plugin | [1](#t-tools-missing) |
| 2 | A template is missing from the list, or listed with `error` | wrong library, or a broken `template.json` | [2](#t-template-missing) |
| 3 | `artifact_from_template` refuses the data | the data does not fit the schema | [3](#t-data-refused) |
| 4 | `artifact_template_save` refuses the template | schema, example, files or limits | [4](#t-save-refused) |
| 5 | The `artifact` CLI says the engine needs Node.js | node is not on PATH | [5](#t-cli-node) |
| 6 | The skill publish-artifact is not offered | a user copy wins, or the node half is not loaded | [6](#t-skill-missing) |
| 7 | `artifact_add` / `artifact_remove` refused, or a de-listed artifact still shows | wrong name or type; the server half (the proxy module) not reloaded | [7](#t-listing) |
| 8 | Media opens as raw bytes, no thumbnails, no download icons | the server module of 2.1 still runs (proxy not restarted), or ffmpeg missing | [8](#t-media) |
| 9 | A download or video seeking fails behind a proxy or service worker | Range or Content-Disposition stripped on the way | [9](#t-download) |
## 0. Collect facts (read-only, always safe)
```bash
# where the plugin is installed (run where dsh web runs)
P=$(node -p "require('path').dirname(require.resolve('dsh-artifacts/package.json',{paths:[(process.env.DSH_HOME||require('os').homedir()+'/.dsh')+'/profiles/web']}))")
echo "$P"; node -p "require('$P/package.json').version"
# the libraries the engine searches, in order, and where agents save templates
node "$P/lib/engine/cli.js" list | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const j=JSON.parse(s);console.log(j.dirs,"save to:",j.write_dir);for(const t of j.templates)console.log(t.id,t.source,t.error||"")})'
# what the node half logged at the last start of dsh web (adapt to how you run it)
journalctl --user -u --since today | grep 'dsh-artifacts:'
```
Healthy log lines: `dsh-artifacts: agent tools registered: artifact_templates, artifact_template_info,
artifact_from_template, artifact_template_save`.
## 1. The agent has no artifact_templates tool
**Likely causes** (most likely first)
1. The plugin was installed or updated but `dsh web` has not been restarted: the node half (tools, skill) loads only at start.
2. The node half could not find the harness tool package (log line `ARTIFACT_TOOLS_UNAVAILABLE`).
3. The kill switch `DSH_ARTIFACTS_TOOLS=0` is set in the environment of `dsh web` (log line `disabled`).
4. A plugin version before 2.1 is installed (no tools at all).
**Diagnose** (read-only)
```bash
node -p "require('$P/package.json').version" # needs 2.1.0 or later
journalctl --user -u --since today | grep 'dsh-artifacts:'
```
No `dsh-artifacts:` line since the last start: cause 1. `ARTIFACT_TOOLS_UNAVAILABLE`: cause 2. `disabled`: cause 3.
**Fix**
- Cause 1 **[HUMAN]**: restart `dsh web` (the chat you are in may run inside it, so a human does it).
- Cause 2 **[HUMAN]**: set `DSH_ARTIFACTS_TOOLS_MAIN=/package.json` (the `@deepseek-ai/dsh` package of the running install, for example `$(npm root -g)/@deepseek-ai/dsh/package.json`) in the environment of `dsh web`, then restart it.
- Cause 3 **[HUMAN]**: remove the variable, restart.
- Meanwhile every agent can use the CLI: `artifact templates`, `artifact template-info `, `artifact new --template --data x.json`, `artifact template-save spec.json`. Same engine, same libraries.
**Verify**: a new chat lists `artifact_templates` among its tools, and the log shows the `agent tools registered` line.
**Related codes:** `ARTIFACT_TOOLS_UNAVAILABLE`, `ARTIFACT_INTERNAL`.
## 2. A template is missing, or listed with an error
**Likely causes**
1. It lives in a library this process does not search: the search order is `$ARTIFACT_TEMPLATES` (colon separated), `~/estate/templates/artifacts`, the user library `${DSH_HOME:-~/.dsh}/artifacts/templates`, then the bundled copy. `dsh web` and your shell may have different `HOME`, `DSH_HOME` or `ARTIFACT_TEMPLATES`.
2. A library searched earlier has a template with the same id (first match wins).
3. Its `template.json` is broken (`ARTIFACT_TEMPLATE_BROKEN`; the list shows `error`).
**Diagnose**: run the `list` command of section 0 and compare `dirs` and `source` with where the folder is.
**Fix**: move the folder into a searched library, or set `ARTIFACT_TEMPLATES` **[HUMAN]** for `dsh web`; rename the id when it collides; fix the JSON named in `error` (or save the template again with `artifact_template_save` and `overwrite: true`).
**Verify**: `artifact_templates` lists the id without `error`.
**Related codes:** `ARTIFACT_TEMPLATE_NOT_FOUND`, `ARTIFACT_TEMPLATE_BROKEN`.
## 3. artifact_from_template refuses the data
**Likely causes**
1. A field does not fit the schema (`ARTIFACT_DATA_INVALID`, see `errors[]`: one entry per field).
2. A local image or video path does not exist (`data.hero.src: file not found: ...`): relative paths resolve against `base_dir`, default the artifacts folder.
3. A credential-shaped string (`ARTIFACT_SECRET_REFUSED`).
4. The name exists (`ARTIFACT_EXISTS`) or is not a slug (`ARTIFACT_BAD_NAME`).
5. The artifacts folder is not writable (`ARTIFACT_WRITE_FAILED`).
**Diagnose**: call `artifact_template_info` and compare the `minimal_example` with your data; call `artifact_from_template` with `check: true` while fixing (writes nothing).
**Fix**: correct the listed fields; pass absolute file paths or `base_dir`; remove secrets; pick another name or `force: true`; for cause 5 check `ls -ld "${ARTIFACT_DIR:-$HOME/reports}"` and `df -h`.
**Verify**: the call returns `ok: true` with `path` and `url`.
**Related codes:** `ARTIFACT_DATA_INVALID`, `ARTIFACT_SECRET_REFUSED`, `ARTIFACT_EXISTS`, `ARTIFACT_BAD_NAME`, `ARTIFACT_WRITE_FAILED`.
## 4. artifact_template_save refuses the template
**Likely causes**
1. A validation problem (`ARTIFACT_TEMPLATE_INVALID`): every one is listed in `errors[]`. The checks: id slug; schema root `{"type": "object", "properties": {...}}` with well-formed keywords; the example fits the schema and its asset files exist in `files`; paths stay inside the folder; the entry file for the kind exists (markdown `template.md`, react the `render` files, motion `composition.html`); a trial render of the example succeeds; title, purpose, when and readme are present.
2. The id exists in the target library (`ARTIFACT_TEMPLATE_EXISTS`): pass `overwrite: true`.
3. The id is taken by a library searched first (`ARTIFACT_TEMPLATE_SHADOWED`): pick another id.
4. Limits (`ARTIFACT_TOO_LARGE`): 512 KB per file, 4 MB per template, 60 files.
5. The target library is not writable (`ARTIFACT_TEMPLATE_READONLY`).
**Diagnose**: `artifact_templates` shows `save_to` (the target library) and the `libraries` with `writable`.
**Fix**: causes 1 to 4 by the agent as described. Cause 5 **[HUMAN]**: make the folder writable, or set `ARTIFACT_TEMPLATES_WRITE=` for `dsh web` (restart). The bundled copy inside the plugin is never a target.
**Verify**: the save returns `ok: true`, and `artifact_templates` lists the id with `source: user` (or `custom`).
**Related codes:** `ARTIFACT_TEMPLATE_INVALID`, `ARTIFACT_TEMPLATE_EXISTS`, `ARTIFACT_TEMPLATE_SHADOWED`, `ARTIFACT_TOO_LARGE`, `ARTIFACT_TEMPLATE_READONLY`, `ARTIFACT_SECRET_REFUSED`, `ARTIFACT_RENDER_FAILED`.
## 5. The artifact CLI says the template engine needs Node.js
The template commands of the CLI run the same TypeScript engine as the tools (`lib/engine/cli.js`).
**Diagnose**: `command -v node`.
**Fix**: put `node` on `PATH` for the shell that runs `artifact`, or set `ARTIFACT_NODE=/path/to/node`.
**Verify**: `artifact templates` prints the list.
## 6. The publish-artifact skill is not offered
**Likely causes**
1. A user copy in `~/.dsh/skills/publish-artifact/` wins over the packaged one (by design) and is older.
2. The node half is not loaded (section 1).
**Fix**: refresh or delete the user copy (`cp -r "$P/skills/publish-artifact" ~/.dsh/skills/`); for cause 2 see section 1.
**Verify**: a new chat offers the skill and its section 0 names the `artifact_*` tools.
## 7. Listing and de-listing
**Likely causes**
1. The name does not match (ARTIFACT_NOT_FOUND) or matches two files (ARTIFACT_AMBIGUOUS): use a `name` from `artifact_list({ include_hidden: true })`, with its extension.
2. The type is not on the allowlist (ARTIFACT_TYPE_UNSUPPORTED): zip it or convert it.
3. De-listed but still in the tab: the tools write `~/reports/.artifacts/listing.jsonl` at once, but the tab reads the index from the server module, which loads the 2.2 code only when its host (the reverse proxy that imports `server/artifacts_server.py`) restarts.
**Fix**: for 3, restart the proxy that serves `/report/` **[HUMAN]**. Nothing is lost meanwhile: the listing file is append only and is read by the new code.
**Verify**: `artifact list --json --hidden` shows `listed: false`; `curl -s "$URL/report/_api/index" | jq .hidden` counts it.
## 8. Media and files open as raw bytes, no thumbnails or download icons
**Likely causes**
1. The 2.1 server module still runs (no `view`, `download`, `thumb` fields in `/report/_api/index`).
2. `ffmpeg`, `ffprobe` (video, audio, images) or `pdftoppm` (PDF) are not installed: no thumbnail, no duration, the kind icon shows instead.
3. `ARTIFACT_THUMBS=0` in the environment of the proxy.
**Fix**: 1, restart the proxy **[HUMAN]**; 2, install ffmpeg and poppler-utils; failed thumbnails are remembered per file version in `.artifacts/thumbs/*.fail` (delete them to retry).
**Verify**: `curl -s -o /dev/null -w '%{http_code} %{content_type}\n' "$URL/report/