FlowiseAI/Flowise · error · Error

Invalid file path: key is required and must be a string

Error message

Invalid file path: key is required and must be a string

What it means

Thrown by getSafeFilePath(baseDir, key) when `key` is falsy or not a string. getSafeFilePath is the hard boundary that resolves an untrusted relative key/filename to an absolute path guaranteed to stay inside baseDir, so it refuses any key it cannot treat as text. The check happens before percent-decoding, null-byte scanning, and the path.relative containment test, so a missing key fails fast and early.

Source

Thrown at packages/components/src/validator.ts:446

    baseName = baseName.replace(/^\.+/, '')
    if (!baseName || isUnsafeFilePath(baseName)) {
        throw new Error(`Invalid or unsafe file name: ${name}`)
    }
    return baseName
}

/**
 * Safely resolve an untrusted relative key/filename to an absolute path inside a
 * trusted base directory, guaranteeing the result cannot escape that directory.
 *
 * @param {string} baseDir The trusted base directory (e.g. a freshly created temp dir)
 * @param {string} key The untrusted relative key or filename
 * @returns {string} A validated absolute path guaranteed to be within baseDir
 * @throws {Error} If key is missing/invalid or the resolved path escapes baseDir
 */
export const getSafeFilePath = (baseDir: string, key: string): string => {
    if (!key || typeof key !== 'string') {
        throw new Error('Invalid file path: key is required and must be a string')
    }

    let decodedKey = key
    try {
        decodedKey = decodeURIComponent(key)
    } catch {
        // malformed percent-encoding — keep the raw key; resolve/relative handle it safely
    }

    if (decodedKey.includes('\0')) {
        throw new Error(`Invalid file path: null byte detected in "${key}"`)
    }

    const resolvedBase = path.resolve(baseDir)
    const resolvedPath = path.resolve(resolvedBase, decodedKey)

    if (process.env.PATH_TRAVERSAL_SAFETY === 'false') {
        return resolvedPath

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Validate the key at the controller boundary and return 400 before calling getSafeFilePath.
  2. Guard with a type check: `if (typeof key !== 'string' || key.length === 0)` then reject the request.
  3. If empty keys are semantically invalid for your flow, assert that upstream (e.g. the upload step that stores the key).

Example fix

// before
const abs = getSafeFilePath(baseDir, req.query.key) // req.query.key may be undefined

// after
const key = req.query.key
if (typeof key !== 'string' || key.length === 0) {
    return res.status(400).json({ message: 'key is required' })
}
const abs = getSafeFilePath(baseDir, key)
Defensive patterns

Strategy: validation

Validate before calling

if (typeof key !== 'string' || key.length === 0) {
    return res.status(400).json({ message: 'A non-empty key is required' })
}
const abs = getSafeFilePath(baseDir, key)

Type guard

const isNonEmptyKey = (v: unknown): v is string =>
    typeof v === 'string' && v.length > 0

Try / catch

try {
    const abs = getSafeFilePath(baseDir, key)
} catch (e) {
    return res.status(400).json({ message: (e as Error).message })
}

Prevention

When it happens

Trigger: Calling getSafeFilePath(tmpDir, undefined), getSafeFilePath(tmpDir, null), getSafeFilePath(tmpDir, ''), or getSafeFilePath(tmpDir, 0). Typically reached from a storage/attachment handler that resolves an object key from a request param, query, or DB column that was null/empty.

Common situations: A route handler that reads req.params.key but the client omitted it; a DB row whose storageKey column is NULL; a refactor that renamed the field and left the old accessor returning undefined; integration tests that pass an empty key.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/88ce9856a28e9001. Report an issue: GitHub.