openclaw - ✅(Solved) Fix [Bug] grammy module not installed causes ERR_MODULE_NOT_FOUND for all users regardless of Telegram usage [1 pull requests, 5 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#59850Fetched 2026-04-08 02:39:47
View on GitHub
Comments
5
Participants
5
Timeline
8
Reactions
1
Timeline (top)
commented ×5cross-referenced ×1mentioned ×1subscribed ×1

Error Message

  • The error is confusing and misleading since the user has no Telegram configuration

Root Cause

api--X4qgagF.js unconditionally imports sticker-cache-BqQLBzvo.js:

// api--X4qgagF.js line 7:
import "./sticker-cache-BqQLBzvo.js";

sticker-cache is a Telegram bot API wrapper. At the top of the compiled file:

// sticker-cache-BqQLBzvo.js line 43:
import * as grammy from "grammy";

This means grammy is loaded statically at startup, not lazily when Telegram is used. As a result, any operation that triggers the API module (e.g., pasting a URL for link preview / OG metadata fetching) will crash if grammy is missing — regardless of whether the user has Telegram configured.

Fix Action

Fixed

PR fix notes

PR #59906: Auto-reply: use telegram facade in approve handler

Description (problem / solution / changelog)

Describe the problem and fix in 2–5 bullets:

  • Problem: src/auto-reply/reply/commands-approve.ts imported extensions/telegram/api.js directly, bypassing the lazy Telegram public-surface facade.
  • Why it matters: that direct extension-barrel import can pull Telegram-only runtime code and dependencies into unrelated command flows, which is exactly the kind of eager-load regression behind recent grammy fallout.
  • What changed: switched the import to src/plugin-sdk/telegram-surface.ts and added src/auto-reply/reply/commands- approve.import-boundary.test.ts to lock the boundary in place.
  • What did NOT change (scope boundary): no /approve behavior, no auth rules, no Telegram business logic, no config/ schema/runtime dependency changes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #59850
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: core /approve handling deep-imported the concrete Telegram extension barrel instead of using the lazy plugin SDK facade. That bypassed the intended boundary and made a broad Telegram surface reachable from core command code.
  • Missing detection / guardrail: there was no focused regression test asserting that commands-approve.ts stayed on the facade path instead of importing extensions/telegram/api.js directly.
  • Prior context (git blame, prior PR, issue, or refactor if known): static review showed src/auto-reply/reply/ commands-approve.ts was the only core src/** import directly reaching into extensions/telegram/api.js; related user reports are tracked in #59850.
  • Why this regressed now: the direct import left core exposed to Telegram-specific bundle/runtime edges, so when Telegram-only dependencies became fragile, unrelated flows were also at risk.
  • If unknown, what was ruled out: ruled out a config-only fix; the issue exists at the import-boundary level in core source.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should have caught this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/auto-reply/reply/commands-approve.import-boundary.test.ts
  • Scenario the test should lock in: commands-approve.ts must import Telegram approval helpers via src/plugin-sdk/ telegram-surface.ts, not extensions/telegram/api.js.
  • Why this is the smallest reliable guardrail: the regression is an import-boundary mistake, so a source-level boundary test is the cheapest direct check for exactly this failure mode.
  • Existing test that already covers this (if any): none found.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

List user-visible changes (including defaults/config). If none, write None.

  • Removes an unintended direct dependency edge from core /approve handling to the Telegram extension barrel.
  • No intended CLI/config behavior change.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

Before: core /approve handler -> extensions/telegram/api.js -> broad Telegram surface

After: core /approve handler -> plugin-sdk/telegram-surface.js -> lazy facade -> Telegram surface only when needed

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Windows 11 workspace host
  • Runtime/container: Not run; static review only per request
  • Model/provider: N/A
  • Integration/channel (if any): Telegram approval helper boundary
  • Relevant config (redacted): N/A

Steps

  1. Inspect src/auto-reply/reply/commands-approve.ts.
  2. Observe the old direct import from extensions/telegram/api.js.
  3. Compare with the intended lazy facade in src/plugin-sdk/telegram-surface.ts.

Expected

  • Core /approve handling should go through the lazy Telegram facade and should not deep-import the concrete extension barrel.

Actual

  • commands-approve.ts directly imported extensions/telegram/api.js, bypassing the facade boundary.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Static trace used for review: src/auto-reply/reply/commands-approve.ts -> ../../../extensions/telegram/api.js replaced with: src/auto-reply/reply/commands-approve.ts -> ../../plugin-sdk/telegram-surface.js

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: traced the old import path, traced the replacement facade path, confirmed the facade exposes the same helper names, and confirmed this was the only core direct import of extensions/telegram/api.js.
  • Edge cases checked: ensured the change is scope-limited to import wiring and does not change /approve parsing, auth, gateway calls, or Telegram approval semantics.
  • What you did not verify: no tests, build, install, or runtime flows were executed.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: the lazy facade enforces the intended plugin boundary, so any hidden reliance on direct extension loading would now fail sooner.
    • Mitigation: this call site only needs Telegram helpers and should already be using the facade; aligning it with the existing public surface removes the unintended eager-load path.
  • Risk: the new regression test is source-text based and can fail on future import-path churn.
    • Mitigation: that brittleness is intentional here because the exact import boundary is what the test is meant to protect.

Changed files

  • src/auto-reply/reply/commands-approve.ts (modified, +1/-1)
  • src/auto-reply/reply/commands.test.ts (modified, +7/-0)

Code Example

// api--X4qgagF.js line 7:
import "./sticker-cache-BqQLBzvo.js";

---

// sticker-cache-BqQLBzvo.js line 43:
import * as grammy from "grammy";

---

// Before (static import, crashes at load time if grammy is missing):
import * as grammy from "grammy";

// After (lazy import, only loads when sticker functions are actually called):
let _grammy;
const grammy = () => (_grammy ??= await import("grammy"));
RAW_BUFFERClick to expand / collapse

Bug Description

grammy is declared as a dependency in package.json but fails to install, causing ERR_MODULE_NOT_FOUND when any URL is pasted in the webchat — even for users who have never configured Telegram.

Root Cause

api--X4qgagF.js unconditionally imports sticker-cache-BqQLBzvo.js:

// api--X4qgagF.js line 7:
import "./sticker-cache-BqQLBzvo.js";

sticker-cache is a Telegram bot API wrapper. At the top of the compiled file:

// sticker-cache-BqQLBzvo.js line 43:
import * as grammy from "grammy";

This means grammy is loaded statically at startup, not lazily when Telegram is used. As a result, any operation that triggers the API module (e.g., pasting a URL for link preview / OG metadata fetching) will crash if grammy is missing — regardless of whether the user has Telegram configured.

Impact

  • Users who do not use Telegram are forced to have the grammy package present
  • The error is confusing and misleading since the user has no Telegram configuration
  • No way to disable this dependency for users who don't need Telegram

Suggested Fix

  1. Short term: Add a CI check to verify node_modules/grammy exists after installation
  2. Medium term: Convert sticker-cache to a dynamic import so it's only loaded when Telegram is actually used
  3. Long term: Consider splitting the Telegram extension into an optional plugin

The dynamic import fix for sticker-cache-BqQLBzvo.js would look something like:

// Before (static import, crashes at load time if grammy is missing):
import * as grammy from "grammy";

// After (lazy import, only loads when sticker functions are actually called):
let _grammy;
const grammy = () => (_grammy ??= await import("grammy"));

Environment

  • OpenClaw: 2026.4.1
  • Node.js: v23.11.0

extent analysis

TL;DR

Implement a dynamic import for the grammy module in sticker-cache-BqQLBzvo.js to prevent it from loading statically at startup.

Guidance

  • Identify all places where grammy is imported statically and consider converting them to dynamic imports to prevent loading the module unnecessarily.
  • Verify that the dynamic import fix works by testing the application with the grammy package missing and then present, ensuring that the error only occurs when the Telegram functionality is actually used.
  • Consider implementing a CI check to ensure that the grammy package is installed correctly, as suggested in the short-term fix.
  • Evaluate the long-term solution of splitting the Telegram extension into an optional plugin to further improve the application's flexibility and user experience.

Example

The provided example in the issue body demonstrates how to convert a static import to a dynamic import:

let _grammy;
const grammy = () => (_grammy ??= await import("grammy"));

This code ensures that the grammy module is only loaded when the grammy function is called, preventing the static loading issue.

Notes

The dynamic import fix assumes that the grammy module is not required for the application to function normally when Telegram is not in use. If this is not the case, additional modifications may be necessary to ensure the application's stability.

Recommendation

Apply the dynamic import workaround to prevent unnecessary loading of the grammy module, as it provides a more immediate solution to the issue and improves the application's overall user experience.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING