FlowiseAI/Flowise · warning · InternalFlowiseError
Error: apikeyController.createApiKey - permissions must be a
Error message
Error: apikeyController.createApiKey - permissions must be an array of strings!
What it means
createApiKey handler validates that req.body.permissions is a non-empty array where every element is a string. Failing any of those checks throws InternalFlowiseError 412. Permissions are stored on the key and used for authorization, so the shape must be correct before the service layer is reached.
Source
Thrown at packages/server/src/controllers/apikey/index.ts:35
const apiResponse = await apikeyService.getAllApiKeys(user, page, limit)
return res.status(StatusCodes.OK).json(apiResponse)
} catch (error) {
next(error)
}
}
const createApiKey = async (req: Request, res: Response, next: NextFunction) => {
try {
if (typeof req.body === 'undefined' || !req.body.keyName) {
throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.createApiKey - keyName not provided!`)
}
if (
!req.body.permissions ||
!Array.isArray(req.body.permissions) ||
req.body.permissions.length === 0 ||
!req.body.permissions.every((p: any) => typeof p === 'string')
) {
throw new InternalFlowiseError(
StatusCodes.PRECONDITION_FAILED,
`Error: apikeyController.createApiKey - permissions must be an array of strings!`
)
}
const user = req.user as LoggedInUser
const apiResponse = await apikeyService.createApiKey(user, req.body.keyName, req.body.permissions)
return res.json(apiResponse)
} catch (error) {
next(error)
}
}
// Update api key
const updateApiKey = async (req: Request, res: Response, next: NextFunction) => {
try {
if (typeof req.params === 'undefined' || !req.params.id) {
throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.updateApiKey - id not provided!`)
}View on GitHub (pinned to abe4a8601a)
Solutions
- Send permissions as a non-empty array of strings, e.g. ["chatflows:read", "chatflows:write"].
- On the client, coerce selected permission values to strings and ensure at least one is chosen.
- If accepting a string shorthand, wrap it client-side: [].concat(value).
- Add a JSON-schema validator at the route to reject malformed arrays with a clearer message.
Example fix
// before
if (!req.body.permissions || !Array.isArray(req.body.permissions) || req.body.permissions.length === 0 || !req.body.permissions.every((p: any) => typeof p === 'string')) {
throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.createApiKey - permissions must be an array of strings!`)
}
// after: clearer status and message
const perms = req.body?.permissions
if (!Array.isArray(perms) || perms.length === 0 || !perms.every((p: unknown): p is string => typeof p === 'string')) {
throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'permissions must be a non-empty array of strings')
} Defensive patterns
Strategy: type-guard
Validate before calling
function requirePermissions(body: any): asserts body is { permissions: string[] } {
const p = body?.permissions
if (!Array.isArray(p) || p.length === 0 || !p.every((x) => typeof x === 'string')) {
throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'permissions must be a non-empty array of strings')
}
}
requirePermissions(req.body) Type guard
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.length > 0 && value.every((x) => typeof x === 'string')
} Try / catch
// Relies on the global error handler mapping InternalFlowiseError.statusCode (412) to HTTP. // To improve, change the thrown status to BAD_REQUEST (400) for clearer client semantics.
Prevention
- Send permissions as a non-empty array of strings.
- Coerce selected permission values to strings and require at least one on the client.
- Wrap single-string shorthand into an array before sending.
- Add a JSON-schema validator at the route to reject malformed arrays early.
When it happens
Trigger: POST to create-api-key with permissions omitted, set to a single string instead of an array, an empty array, or an array containing non-string entries (numbers, objects, null).
Common situations: Client sends permissions: 'chatflows:read' (string) instead of ['chatflows:read']. Frontend sends [] when nothing selected. Mixed-type array from a loosely typed form. Legacy client using a comma-separated string.
Related errors
- Error: apikeyController.updateApiKey - permissions must be a
- Error: apikeyController.createApiKey - keyName not provided!
- Error: apikeyController.updateApiKey - id not provided!
- Error: apikeyController.updateApiKey - keyName not provided!
- Question and selectedChatModel are required
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/8ccdbfa043451f8f.
Report an issue: GitHub.