laurent22/joplin · error · JoplinError

fileNotFound

fileNotFound

Error message

File not found: ${options.path}

What it means

Thrown by FileApi.put() when options.source === 'file' but the local file at options.path does not exist (checked via fsDriver().exists). The driver refuses to attempt a streaming upload of a missing file rather than letting the underlying driver fail with a cryptic stream error.

Source

Thrown at packages/lib/file-api.ts:405

		if (!output) return output;
		output.path = path;
		return output;
	}

	// Returns UTF-8 encoded string by default, or a Response if `options.target = 'file'`
	public get(path: string, options: GetOptions = null) {
		if (!options) options = {};
		if (!options.encoding) options.encoding = 'utf8';
		logger.debug(`get ${this.fullPath(path)}`);
		return tryAndRepeat(() => this.driver_.get(this.fullPath(path), options), this.requestRepeatCount());
	}

	public async put(path: string, content: string | Buffer | null, options: PutOptions = null) {
		logger.debug(`put ${this.fullPath(path)}`, options);

		if (options && options.source === 'file') {
			if (!(await this.fsDriver().exists(options.path))) throw new JoplinError(`File not found: ${options.path}`, 'fileNotFound');
		}

		return tryAndRepeat(() => this.driver_.put(this.fullPath(path), content, options), this.requestRepeatCount());
	}

	public async multiPut(items: MultiPutItem[], options: { source?: string } = null) {
		if (!this.driver().supportsMultiPut) throw new Error('Multi PUT not supported');
		return tryAndRepeat(() => this.driver_.multiPut(items, options), this.requestRepeatCount());
	}

	public async multiDelete(paths: string[]) {
		if (!this.supportsMultiDelete) throw new Error('Multi DELETE not supported');
		return tryAndRepeat(() => this.driver_.multiDelete(paths), this.requestRepeatCount());
	}

	public delete(path: string) {
		logger.debug(`delete ${this.fullPath(path)}`);
		return tryAndRepeat(() => this.driver_.delete(this.fullPath(path)), this.requestRepeatCount());

View on GitHub (pinned to 2654b33620)

Solutions

  1. Verify the file exists with fsDriver().exists(options.path) immediately before calling put() and handle the race if it may be deleted concurrently.
  2. Check the path is absolute and correct (no trailing slash, correct extension, right working directory).
  3. If the file is a temp resource being processed, ensure no concurrent cleanup (e.g. disable parallel garbage collection during sync).
  4. Regenerate or restore the missing source file before retrying.

Example fix

// before
await fileApi.put(remotePath, null, { source: 'file', path: localPath });
// after - guard before the call
if (!(await shim.fsDriver().exists(localPath))) {
  throw new Error(`Source file vanished before upload: ${localPath}`);
}
await fileApi.put(remotePath, null, { source: 'file', path: localPath });
Defensive patterns

Strategy: validation

Validate before calling

if (options?.source === 'file') {
  if (!(await shim.fsDriver().exists(options.path))) {
    throw new Error(`Cannot upload: source file missing: ${options.path}`);
  }
}

Type guard

function isFileSourceUpload(options: any): options is { source: 'file'; path: string } {
  return options && options.source === 'file' && typeof options.path === 'string';
}

Try / catch

try {
  await fileApi.put(remotePath, null, { source: 'file', path: localPath });
} catch (e) {
  if (e.code === 'fileNotFound' && /File not found/.test(e.message)) {
    // source vanished - regenerate, restore, or skip
    logger.warn('Upload skipped, source missing:', localPath);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling fileApi.put(path, null, { source: 'file', path: '/local/file.md' }) where /local/file.md has been moved, deleted, or the path is wrong before the PUT runs.

Common situations: Resource file was deleted between scheduling the upload and executing it; temp file already cleaned up by a concurrent process; wrong path passed (relative vs absolute, missing extension); external editor moved the file; antivirus quarantined the file on Windows.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/4d8f1b3a1c59374a. Report an issue: GitHub.