jackwener/OpenCLI · error · ArgumentError
file is empty: ${abs}
Error message
file is empty: ${abs} What it means
This ArgumentError is thrown by the attachment upload pre-flight check when fs.statSync reports the file at the resolved path has size 0. The CLI validates local files against the Slock server's constraints before reading or uploading them, and an empty file can never be a meaningful attachment, so it fails fast with the absolute path in the message.
Source
Thrown at clis/slock/attachment-upload.js:58
browser: true,
siteSession: 'persistent',
args: [
{ name: 'file', positional: true, required: true, help: 'Local file path to upload (single file; max 50 MB)' },
{ name: 'channel', positional: true, required: true, help: 'channelId UUID or #name — server requires the attachment be scoped to a channel' },
{ name: 'server', help: 'Override active server slug' },
],
columns: ['attachmentId', 'filename', 'mimeType', 'sizeBytes'],
func: async (page, kwargs) => {
const filePath = String(kwargs.file ?? '').trim();
if (!filePath) throw new ArgumentError('file path required');
const channel = String(kwargs.channel ?? '').trim();
if (!channel) throw new ArgumentError('channel required (UUID or #name); server rejects uploads without channelId');
const abs = path.resolve(filePath);
let stat;
try { stat = fs.statSync(abs); }
catch (e) { throw new ArgumentError(`file not readable: ${abs} (${e.message})`); }
if (!stat.isFile()) throw new ArgumentError(`not a regular file: ${abs}`);
if (stat.size === 0) throw new ArgumentError(`file is empty: ${abs}`);
if (stat.size > MAX_BYTES) {
throw new ArgumentError(`file is ${stat.size} bytes, exceeds server limit ${MAX_BYTES} (50 MiB). Split or compress before upload.`);
}
const buf = fs.readFileSync(abs);
const filename = path.basename(abs);
const b64 = buf.toString('base64');
await page.goto(SLOCK_HOME_URL);
const snippet = `
${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}
${channelResolveFragment(channel)}
// multipart wants the browser to set its own boundary — strip content-type.
const uploadHeaders = { authorization: headers.authorization, accept: headers.accept };
if (headers['x-server-id']) uploadHeaders['x-server-id'] = headers['x-server-id'];
// Rebuild File from base64 → Uint8Array → Blob → File. The base64 string
// is the only path across the page boundary; JSON.stringify it (caller did)View on GitHub (pinned to 49907e53dc)
Solutions
- Check the file size before invoking: `ls -la <file>` or `stat -c %s <file>`; it must be > 0 bytes.
- Regenerate the file with the producing tool/command and confirm it has content.
- Verify you are pointing at the correct file, not a placeholder or partially-written temp file.
- If the file is intentionally empty, reconsider whether an attachment upload is appropriate; the server would reject it anyway.
Example fix
// before
await uploadAttachment(page, '/tmp/empty.log');
// after
const fs = require('fs');
if (fs.statSync('/tmp/empty.log').size === 0) throw new Error('refusing to upload empty file');
await uploadAttachment(page, '/tmp/empty.log'); Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const stat = fs.statSync(filePath);
if (stat.size === 0) throw new Error(`refusing to upload empty file: ${filePath}`); Type guard
const isNonEmptyFile = (p) => { try { const s = fs.statSync(p); return s.isFile() && s.size > 0; } catch { return false; } }; Try / catch
try {
await uploadAttachment(page, filePath);
} catch (e) {
if (e instanceof ArgumentError && e.message.includes('file is empty')) {
console.error(`Skip ${filePath}: empty file`);
} else throw e;
} Prevention
- Check stat.size > 0 before any upload call.
- In pipelines, assert the producing step wrote bytes (exit code + file size).
- Use isNonEmptyFile() as a filter before batch uploads.
When it happens
Trigger: Calling the attachment-upload command with filePath pointing at a 0-byte regular file, e.g. a file created by `touch`, a truncated download, or a log that was rotated/emptied.
Common situations: CI pipelines creating placeholder files, redirecting output incorrectly (`> file` with a failing command), disk-full truncation, or passing a temp file that a producer process hasn't finished writing yet.
Related errors
- 封面文件不存在: ${path.resolve(coverPath)}
- not a regular file: ${abs}
- file is ${stat.size} bytes, exceeds server limit ${MAX_BYTES
- ${label}文件不存在: ${resolved}
- Not a valid file: ${absPath}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0221827324954bf2.
Report an issue: GitHub.