Skip to content

[Bug]: Tool-output file uploads fail with EACCES because scratch files are written into the installed package (dist/.tmp) #286

Open

Description

@Realmagnum

What happens

Every tool-output file the bot tries to deliver to Telegram is dropped with EACCES when the package is installed globally and the bot runs as an unprivileged user:

[2026-10-23T08:39:45.128Z] [ERROR] [ToolBatcher] Failed to send tool file message: session=ses_..., reason=enqueue_file Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/@grinev/opencode-telegram-bot/dist/.tmp'

The assistant's reply is still delivered, but the attached file (write/edit summary, diff) never reaches the chat.

Environment

  • opencode-telegram-bot 0.26.5 (npm i -g @grinev/opencode-telegram-bot)
  • Node.js v24.21.0, Linux x64
  • Bot started from a systemd unit as an unprivileged user (srv)
  • Global npm prefix is root-owned: /usr/lib/node_modules/@grinev/opencode-telegram-bot is drwxr-xr-x root root

Root cause

src/bot/events/telegram-event-delivery.ts:19:

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const TEMP_DIR = path.join(__dirname, "..", "..", ".tmp");

In the built package that resolves to <package>/dist/.tmp. sendDocument() then calls fs.mkdir(TEMP_DIR, { recursive: true }) and fs.writeFile(...), which requires write access inside the installed package. That is true for a root install (npm i -g, Docker image, distro package), so the very first upload fails.

The same code path is fine only when the bot is started from a writable source checkout or as root — which is why this does not show up in local development.

Expected

Scratch files for outgoing documents should be written to a directory the bot process owns, e.g. under os.tmpdir(), regardless of how the package was installed.

Workaround

sudo mkdir -p /usr/lib/node_modules/@grinev/opencode-telegram-bot/dist/.tmp
sudo chown "$USER" /usr/lib/node_modules/@grinev/opencode-telegram-bot/dist/.tmp

This restores uploads until the next npm update -g, which recreates the package directory and drops the permission fix.

Proposed fix

Use the OS temp directory instead of the package directory:

const TEMP_DIR = path.join(os.tmpdir(), "opencode-telegram-bot");

os.tmpdir() is writable for the process (and honours TMPDIR), so no installation layout or ownership can break it. I have a PR ready: #287.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions