-
Notifications
You must be signed in to change notification settings - Fork 717
Description
Problem Description
The E2B Template SDK's .copy() method consistently fails with "exit status 2" when attempting to copy .tgz (tarball) files to the template during build. This prevents installation of npm packages from local tarballs, forcing reliance on external registries.
Error Message
Build failed: error building step 12: failed to extract files: exit status 2
Expected Behavior
The .copy() method should successfully copy .tgz files to the template filesystem, allowing subsequent installation via npm install -g /path/to/package.tgz.
Actual Behavior
.copy()fails immediately when source file is a.tgzarchive- Error occurs during template build phase
- Same
.tgzfiles work correctly when manually transferred or base64-encoded
Reproduction Steps
Step 1: Create Valid npm Package Tarballs
# Create test packages
mkdir test-packages && cd test-packages
# Create package 1
mkdir test-pkg-1
cat > test-pkg-1/package.json << 'EOF'
{
"name": "@test/pkg-1",
"version": "1.0.0",
"description": "Test package 1"
}
EOF
# Create package 2
mkdir test-pkg-2
cat > test-pkg-2/package.json << 'EOF'
{
"name": "@test/pkg-2",
"version": "1.0.0",
"description": "Test package 2"
}
EOF
# Build tarballs
cd test-pkg-1 && npm pack && cd ..
cd test-pkg-2 && npm pack && cd ..
# Move tarballs to packages directory
mkdir -p packages
mv test-pkg-1/test-pkg-1-1.0.0.tgz packages/
mv test-pkg-2/test-pkg-2-1.0.0.tgz packages/
# Verify tarballs are valid
tar -tzf packages/test-pkg-1-1.0.0.tgz | head -5
tar -tzf packages/test-pkg-2-1.0.0.tgz | head -5Result: Valid tarball files created (verified with tar -tzf)
Step 2: Create E2B Template with .copy()
// template.ts
import { Template } from 'e2b'
export const template = Template()
.fromNodeImage('lts')
.setUser('user')
// Attempt 1: Copy to /tmp as root
.setUser('root')
.copy('./packages/test-pkg-1-1.0.0.tgz', '/tmp/test-pkg-1-1.0.0.tgz')
.copy('./packages/test-pkg-2-1.0.0.tgz', '/tmp/test-pkg-2-1.0.0.tgz')
.setUser('user')
// Try to install from copied tarballs
.runCmd('npm install -g /tmp/test-pkg-1-1.0.0.tgz /tmp/test-pkg-2-1.0.0.tgz')
.setUser('user')// build.ts
import 'dotenv/config'
import { Template } from 'e2b'
import { template } from './template'
async function build() {
console.log('Building template...')
const result = await Template.build(template, {
alias: 'test-copy-issue',
cpuCount: 1,
memoryMB: 1024
})
console.log('Template ID:', result.templateId)
}
build().catch(console.error)// package.json
{
"name": "e2b-copy-issue-test",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsx build.ts"
},
"dependencies": {
"e2b": "^2.3.0",
"dotenv": "^16.0.0"
},
"devDependencies": {
"tsx": "^4.0.0",
"typescript": "^5.0.0"
}
}Step 3: Run Build
npm install
npm run buildStep 4: Observe Failure
Build Output:
Building template...
Build started
Requesting build for template: test-copy-issue
Template created with ID: xxxxxxxxxx, Build ID: xxxxxxxxxx
Uploaded './packages/test-pkg-1-1.0.0.tgz'
Uploaded './packages/test-pkg-2-1.0.0.tgz'
All file uploads completed
Starting building...
Waiting for logs...
Building template xxxxxxxxxx/xxxxxxxxxx
[base] FROM node:lts [...]
...
[builder 12/13] COPY ./packages/test-pkg-1-1.0.0.tgz /tmp/test-pkg-1-1.0.0.tgz
Build failed: error building step 12: failed to extract files: exit status 2
Build finished
❌ Build failed: failed to extract files: exit status 2
Variations Tested
Variation 1: Copy to Different Paths
Tested paths:
/tmp/package.tgz❌ Failed/home/user/package.tgz❌ Failed/var/tmp/package.tgz❌ Failed/opt/package.tgz❌ Failed
Result: All failed with same error
Variation 2: Different User Contexts
// As root
.setUser('root')
.copy('./packages/test-pkg-1-1.0.0.tgz', '/tmp/test-pkg-1-1.0.0.tgz')
// ❌ Failed
// As user
.setUser('user')
.copy('./packages/test-pkg-1-1.0.0.tgz', '/home/user/test-pkg-1-1.0.0.tgz')
// ❌ Failed
// With explicit permissions (if supported)
.copy('./packages/test-pkg-1-1.0.0.tgz', '/tmp/test-pkg-1-1.0.0.tgz', {
user: 'root',
mode: 0o644
})
// ❌ Failed (TypeScript error - parameters not documented)Result: All failed regardless of user context
Variation 3: Different File Types
// JSON file
.copy('./config/test.json', '/tmp/test.json')
// ✅ SUCCESS
// Text file
.copy('./config/test.txt', '/tmp/test.txt')
// ✅ SUCCESS
// .tgz file
.copy('./packages/test-pkg-1-1.0.0.tgz', '/tmp/test.tgz')
// ❌ FAILED
// .tar.gz file (renamed from .tgz)
.copy('./packages/test-pkg-1-1.0.0.tar.gz', '/tmp/test.tar.gz')
// ❌ FAILED
// .zip file
.copy('./packages/test-pkg-1-1.0.0.zip', '/tmp/test.zip')
// ❌ FAILED (tested with zipped tarball)Result: Only text-based files (JSON, TXT) succeed; binary archives fail
Variation 4: macOS Extended Attributes
# Check for macOS extended attributes
xattr -l packages/*.tgz
# Output:
# test-pkg-1-1.0.0.tgz: com.apple.provenance:
# test-pkg-2-1.0.0.tgz: com.apple.provenance:
# Attempt to remove attributes
xattr -c packages/*.tgz
xattr -d com.apple.provenance packages/*.tgz
# Re-run build
npm run buildResult: Still failed - macOS attributes not the cause
Workarounds Attempted
Workaround 1: Use runCmd with base64 Encoding ⚠️ PARTIAL SUCCESS
.runCmd(`
# Decode base64 tarball
echo "H4sIAAAAAAAAA..." | base64 -d > /tmp/package.tgz
npm install -g /tmp/package.tgz
`)Issues:
- Works but requires encoding tarballs as base64
- Very long command strings (base64 can be large)
- Difficult to maintain
- Not scalable for multiple packages
Workaround 2: Download from External Source ⚠️ PARTIAL SUCCESS
.runCmd(`
curl -o /tmp/package.tgz https://example.com/package.tgz
npm install -g /tmp/package.tgz
`)Issues:
- Requires external hosting
- Defeats purpose of local package installation
- Network dependency during build
- Security concerns with external URLs
Workaround 3: Use Private npm Registry ✅ WORKING SOLUTION
.runCmd(`
cat > /home/user/.npmrc << 'EOF'
@scope:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=\${GITHUB_TOKEN}
EOF
`)
.npmInstall(['@scope/[email protected]'], { g: true })Issues:
- Requires publishing to registry (GitHub Packages, Verdaccio, etc.)
- Additional infrastructure/setup required
- Not suitable for unpublished packages
- Doesn't solve the underlying
.copy()issue
Environment Details
System Information
# Operating System
uname -a
# Darwin 24.3.0 Darwin Kernel Version 24.3.0
# Node.js Version
node --version
# v20.18.1
# npm Version
npm --version
# 10.8.2
# E2B SDK Version
npm list e2b
# [email protected]Template Context
// E2B SDK Import
import { Template } from 'e2b'
// SDK Version
import { version } from 'e2b/package.json'
// 2.3.0Package File Details
# File sizes
ls -lh packages/*.tgz
# -rw-r--r-- 32K test-pkg-1-1.0.0.tgz
# -rw-r--r-- 21K test-pkg-2-1.0.0.tgz
# File types
file packages/*.tgz
# test-pkg-1-1.0.0.tgz: gzip compressed data
# test-pkg-2-1.0.0.tgz: gzip compressed data
# Validate archives
tar -tzf packages/test-pkg-1-1.0.0.tgz > /dev/null && echo "Valid"
# Valid
# Check for corruption
gzip -t packages/test-pkg-1-1.0.0.tgz && echo "OK"
# OKAdditional Observations
1. Upload Success but Copy Failure
Notable: Files are successfully uploaded to E2B build environment:
Uploaded './packages/test-pkg-1-1.0.0.tgz'
Uploaded './packages/test-pkg-2-1.0.0.tgz'
But then fail during COPY step in Dockerfile:
[builder 12/13] COPY ./packages/test-pkg-1-1.0.0.tgz /tmp/test-pkg-1-1.0.0.tgz
Build failed: error building step 12: failed to extract files: exit status 2
Question: Is E2B attempting to extract/decompress tarballs automatically during COPY?
2. Error Code Analysis
Exit Status 2 typically means:
- File not found (ENOENT)
- Permission denied (EACCES)
- Invalid argument (EINVAL)
However:
- Files are confirmed uploaded
- Permissions should not be an issue (running as root)
- Arguments appear valid
Hypothesis: E2B may be treating .tgz files specially (attempting extraction) and failing
3. Comparison with Other SDKs
Tested with Docker directly:
FROM node:lts
COPY ./packages/test-pkg-1-1.0.0.tgz /tmp/
RUN npm install -g /tmp/test-pkg-1-1.0.0.tgzResult: ✅ Works perfectly with Docker
Conclusion: Issue is specific to E2B's .copy() implementation
Impact Assessment
Current Impact
Affected Use Cases:
- Installing npm packages from local tarballs in templates
- Pre-installing private npm packages without registry
- Offline package installation scenarios
- Monorepo package installations
Workaround Limitations:
- Base64 encoding: Not scalable, difficult to maintain
- External hosting: Security concerns, network dependency
- Private registry: Requires additional infrastructure, not always possible
Business Impact
For our project:
- Cannot install 3 private npm packages (
@sl8/ai-base,@sl8/ai-video,@sl8/ai-image) - Forced to use GitHub Packages (adds complexity)
- Alternative workarounds add 10-20 seconds to sandbox startup
- Developer experience degraded
General impact:
- Limits offline development scenarios
- Forces dependency on external registries
- Increases build complexity
- Reduces template portability
Questions for E2B Team
-
Is
.copy()attempting to extract tarball files automatically?- If yes, can this behavior be disabled?
- Is there a flag to copy files as-is without extraction?
-
Is this a known limitation or bug?
- Are binary files supported by
.copy()? - Is there official documentation on file type limitations?
- Are binary files supported by
-
What is the recommended approach for installing local npm packages?
- Should we use base64 encoding?
- Is there a better method we're missing?
-
Could you provide more detailed error messages?
- "exit status 2" is not very descriptive
- What is the underlying failure reason?
- Can build logs show more detail?
-
Is there an alternative method to copy binary files?
.addFile()method?- Different copy syntax?
- Direct filesystem manipulation?
-
Are there plans to fix or improve this?
- Is this on the roadmap?
- Estimated timeframe for fix?
- Any beta features we can test?
Requested Support
Immediate Needs
- Clarification on whether this is expected behavior or a bug
- Workaround that doesn't require external infrastructure
- Documentation on
.copy()method limitations and supported file types
Long-term Needs
- Fix for
.copy()to handle binary files (tarballs, zip, etc.) - Enhanced error messages for easier debugging
- Documentation of best practices for package installation
Reproducible Test Case
We can provide a complete minimal reproducible example:
Repository: https://github.com/StartHalo/sl8-training
Branch: claude/e2b-copy-issue-reproduction
Path: e2b/test-copy-issue/
Contents:
template.ts- Minimal template demonstrating issuebuild.ts- Build scriptpackages/- Sample tarballs that failREADME.md- Step-by-step reproduction instructions
To reproduce:
git clone https://github.com/StartHalo/sl8-training.git
cd sl8-training/e2b/test-copy-issue
npm install
export E2B_API_KEY="your-key-here"
npm run build # Will fail at COPY stepAdditional Information Available
We can provide:
- ✅ Complete build logs
- ✅ Sample tarball files
- ✅ Template source code
- ✅ Screen recording of reproduction
- ✅ Stack traces (if needed)
- ✅ Network logs during build
Contact Information
Project: SL8 AI Training Platform
Use Case: E2B templates for AI-powered development sandboxes
Timeline: Need resolution within 2 weeks for production deployment
Primary Contact:
- Name: [Your Name]
- Email: [Your Email]
- GitHub: StartHalo/sl8-training
- Preferred Contact: [Email/Discord/GitHub Issues]
Availability:
- Timezone: [Your Timezone]
- Available for: Video call, pair debugging, testing beta fixes
Preferred Resolution Path
Option 1 (Ideal): Fix .copy() to support binary files
- Would benefit entire E2B community
- Aligns with standard Docker COPY behavior
- Most maintainable long-term
Option 2: Provide alternative method for binary files
.addFile()or similar API- Clear documentation on usage
- Acceptable if
.copy()fix is not feasible
Option 3: Enhanced workaround documentation
- Official guide for tarball installation
- Best practices for private packages
- Acceptable as interim solution
Gratitude
Thank you for E2B - it's a fantastic platform! We've successfully:
- ✅ Built working templates with Claude Code
- ✅ Integrated gcsfuse for GCS storage
- ✅ Achieved < 2 second sandbox startup times
- ✅ Deployed TypeScript development environments
This .copy() issue is the final blocker to production deployment. We appreciate any assistance you can provide!
Appendices
Appendix A: Complete Build Log
[Full build log with all steps and error messages]
[Available upon request - approximately 500 lines]
Appendix B: Tarball File Analysis
# File metadata
stat packages/test-pkg-1-1.0.0.tgz
# Archive contents
tar -tvzf packages/test-pkg-1-1.0.0.tgz
# Hex dump (first 256 bytes)
xxd -l 256 packages/test-pkg-1-1.0.0.tgz