Eugeny/tabby · warning · Error

Nothing selected

Error message

Nothing selected

What it means

Thrown by VaultFileProvider.addNewFile when `platform.startUpload()` returns an empty transfers array - i.e. the user dismissed the file picker or selected nothing. There is no file content to store, so the operation cannot proceed.

Source

Thrown at tabby-core/src/services/vault.service.ts:309

                    result: null,
                },
                ...files.map(f => ({
                    name: f.key.description,
                    icon: 'fas fa-file',
                    result: f,
                })),
            ]).catch(() => null)
            if (result) {
                return `${this.prefix}${result.key.id}`
            }
        }
        return this.addNewFile(description)
    }

    async addNewFile (description: string): Promise<string> {
        const transfers = await this.platform.startUpload()
        if (!transfers.length) {
            throw new Error('Nothing selected')
        }
        const transfer = transfers[0]
        const id = (await wrapPromise(this.zone, promisify(crypto.randomBytes)(32))).toString('hex')
        await this.vault.addSecret({
            type: VAULT_SECRET_TYPE_FILE,
            key: {
                id,
                description: `${description} (${transfer.getName()})`,
            },
            value: Buffer.from(await transfer.readAll()).toString('base64'),
        })
        return `${this.prefix}${id}`
    }

    async retrieveFile (key: string): Promise<Buffer> {
        if (!key.startsWith(this.prefix)) {
            throw new Error('Incorrect type')
        }

View on GitHub (pinned to 14e2d60b9b)

Solutions

  1. Treat this as a user cancel: catch the error in the calling flow and abort the import silently (no error toast).
  2. Confirm the host platform implements `startUpload` (Electron does via dialog; web/headless may not).
  3. If the picker should not be cancellable, disable the cancel button in the dialog options passed to `startUpload`.
  4. Differentiate 'Nothing selected' from real failures by inspecting the error message in the caller.

Example fix

// before
const transfers = await this.platform.startUpload()
if (!transfers.length) throw new Error('Nothing selected')

// after - distinguish user cancel from platform failure and surface accordingly
const transfers = await this.platform.startUpload()
if (!transfers.length) {
    throw new Error('Nothing selected')  // caller maps this to a silent abort
}
// caller:
try { await provider.selectAndStoreFile('Private key') }
catch (e) { if (!/Nothing selected/.test(e.message)) throw e }
Defensive patterns

Strategy: try-catch

Validate before calling

async function pickFileOrAbort (platform: PlatformService): Promise<Transfer[]> {
    const transfers = await platform.startUpload()
    if (!transfers.length) throw new Error('Nothing selected')
    return transfers
}

Try / catch

try {
    return await provider.selectAndStoreFile('Private key')
} catch (e) {
    if (e instanceof Error && e.message === 'Nothing selected') return null  // user cancel
    throw e
}

Prevention

When it happens

Trigger: After the user picks 'Add a new file' (or no existing files exist to choose from), `startUpload()` opens a native picker; if the user cancels it or selects zero files, `transfers.length === 0` and this throws.

Common situations: User cancels the OS file-open dialog while importing a private key or other secret; the picker failed to launch (permissions/manifest issue) and returned empty; a non-Electron platform where `startUpload` is a stub returning [].

Related errors


AI-assisted analysis of Eugeny/tabby@14e2d60b9b (2026-08-12). Data as JSON: /api/errors/67a0a8fa84e6daa1. Report an issue: GitHub.