Fix: TypeError basex is not a function ElizaOS plugin-evm Startup
If your ElizaOS agent crashes during the evmPlugin initialization with a TypeError: basex is not a function, the issue is a breaking dependency conflict in the base-x library. This typically occurs when a fresh install pulls an incompatible ESM-only version of base-x into a CommonJS runtime environment.
Diagnostic Stack Trace
TypeError: basex is not a function
at Object.<anonymous> (.../node_modules/@noble/curves/abstract/utils.js:4:32)
at Module._compile (node:internal/modules/cjs/loader:1358:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
...
at initializeEVMPlugin (elizaos/plugin-evm/src/index.ts:12:5)
Immediate Fix: Execute the following command to force-install the compatible version and clear your build cache:
npm install base-x@4.0.0 --save-exact && rm -rf node_modules && npm install
Architectural Context: ESM vs. CommonJS Module Fragmentation
The elizaos/plugin-evm relies heavily on viem and the underlying @noble/curves library for cryptographic operations. These libraries utilize base-x for encoding and decoding the 32-byte scalars required for secp256k1 signature validation. The conflict arises because the JavaScript ecosystem is currently in a state of fragmented transition between CommonJS (CJS) and ECMAScript Modules (ESM).
When the TypeScript compiler or the runtime environment (Node.js) attempts to initialize the evmPlugin, it encounters a require() call pointing to a base-x build that only exports a default ESM object. This mismatch results in the basex variable being undefined or a non-callable object rather than the expected constructor function. This failure is as catastrophic for agent startup as a tealstreet hyperliquid vault shows 0 balance after linking is for a quantitative trading execution loop.
The Cryptographic Role of base-x
In the context of blockchain agents, base-x is often used to implement Base58 encoding (popularized by Bitcoin) or Base32/Base64 variants. For the EVM, while addresses are primarily hexadecimal, the underlying secp256k1 curve logic in @noble/curves uses base-x to handle alphabet-specific transformations for various cross-chain bridging identifiers and metadata.
Specifically, the @noble/curves/abstract/utils.js file attempts to import base-x to provide utility functions for the library. If the import fails to resolve to the function-style constructor (which was standard in version 4.x and below), any downstream call—such as basex(ALPHABET)—will throw the TypeError. This is a classic “Supply Chain Poisoning” scenario, albeit an unintentional one caused by the “dual-package hazard” where a library provides both CJS and ESM builds but the consumer’s bundler selects the wrong entry point.
Bundler Interference and Transpilation
Modern AI agent frameworks like ElizaOS often use a complex build pipeline involving esbuild or swc for fast transpilation. These tools are designed to handle ESM natively, but when they encounter legacy CJS dependencies that try to “reach out” and import modern ESM sub-dependencies, the resolution logic can break. In the case of base-x, version 5.0.0 introduced a breaking change by moving to a pure ESM export. For a CJS-based ElizaOS runtime, the require('base-x') call returns an object { default: [Function] } instead of the function itself. Since the code expects const basex = require('base-x'); basex(), it fails because it is essentially trying to call ({ default: [Function] })().
Preventative Maintenance: Monorepo and CI/CD Immunization
To prevent mismatched upstream library builds from crashing your production deployment, you must implement strict version overrides in your root package.json. This is especially critical in monorepo structures (using pnpm or yarn workspaces) where different plugins might pull in different versions of the same dependency.
1. Root-Level Dependency Resolution
Add the following block to your package.json to immunize your environment across all package managers. This forces every sub-dependency in the tree—regardless of where it is called—to use the verified, compatible version of base-x.
{
"name": "eliza-agent-infrastructure",
"dependencies": {
"@elizaos/plugin-evm": "latest",
"base-x": "4.0.0"
},
"overrides": {
"base-x": "4.0.0",
"@noble/curves": {
"base-x": "4.0.0"
}
},
"resolutions": {
"base-x": "4.0.0"
},
"pnpm": {
"overrides": {
"base-x": "4.0.0"
}
}
}
2. Automated Supply Chain Auditing
Implement a preinstall or postinstall script that checks for the existence of duplicate or incompatible versions of base-x in your node_modules. This prevents “silent” updates from sneaking into your lockfile.
// scripts/check-dependencies.js
const fs = require('fs');
const path = require('path');
function checkBaseX() {
const lockfilePath = path.join(__dirname, '../package-lock.json');
if (!fs.existsSync(lockfilePath)) return;
const lockfile = JSON.parse(fs.readFileSync(lockfilePath, 'utf8'));
const versions = [];
// Recursive search logic for base-x versions
function findVersion(obj) {
for (const key in obj) {
if (key === 'base-x') versions.push(obj[key].version);
if (typeof obj[key] === 'object') findVersion(obj[key]);
}
}
findVersion(lockfile);
if (versions.some(v => v.startsWith('5'))) {
console.error('CRITICAL ERROR: Incompatible base-x v5.x detected in lockfile.');
process.exit(1);
}
}
checkBaseX();
3. Docker-Based Environment Locking
When building Docker images for ElizaOS, ensure you are using a fixed base image and clearing the cache effectively. Use the following multi-stage build pattern to ensure a clean dependency tree:
FROM node:20-slim AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
# Force clean install with frozen lockfile
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# Manually verify the base-x version before building
RUN ls node_modules/base-x/package.json && grep '"version": "4.0.0"' node_modules/base-x/package.json
COPY . .
RUN pnpm build
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
Security Policies for Cryptographic AI Agents
Operating an AI agent with EVM signing authority requires more than just fixing dependency bugs; it requires a holistic security policy to protect the agent’s cryptographic primitives.
- Immutability Policy: Never allow the agent to update its own
package.jsonornode_modulesat runtime. All dependency changes must go through a CI/CD pipeline with automated vulnerability scanning (e.g., Snyk or GitHub Advanced Security). - Runtime Sandboxing: Execute the EVM plugin within a worker thread or a separate container that has limited access to the agent’s core memory. This prevents a compromised dependency (like a malicious
base-xfork) from exfiltrating theEVM_PRIVATE_KEYenvironment variable. - Audit Logs: Implement structured logging for every call to the cryptographic utilities. If the
basexfunction is called, log the input length and the calling module, but never the sensitive data itself.
Advanced FAQ Layer
Q1: Can I just use bs58 instead of base-x to avoid this error?
While bs58 is a popular alternative, it actually uses base-x internally for its heavy lifting. Switching to bs58 won’t solve the problem if the underlying base-x dependency is still being resolved to the ESM-only v5.x. The only permanent fix is to force the resolution at the package manager level as shown in the “Base” section.
Q2: Does this error affect non-EVM plugins in ElizaOS?
Yes, potentially. Any plugin that utilizes cryptographic libraries (like plugin-solana or plugin-bitcoin) is at risk if they share the @noble/curves dependency chain. Since most modern crypto libraries have migrated to @noble primitives, a single base-x conflict can paralyze an agent’s ability to interact with multiple blockchain networks simultaneously.
Q3: Why doesn’t ElizaOS just upgrade to ESM to fix this? Migrating a large codebase like ElizaOS to pure ESM is a non-trivial task that requires updating every single internal module and third-party dependency. Many legacy AI and machine learning libraries still rely on CJS-specific behaviors. Until the entire ecosystem matures, the “override and lock” strategy remains the industry standard for production stability.