balderdashy/sails · warning
Ignoring unexpected property in one of the exits of the help
Error message
Ignoring unexpected property in one of the exits of the helper definition loaded from ${helperDef._loadedFrom}. Features like `responseType`, `viewTemplatePath`, and `statusCode` can only be used by actions, not by helpers! What it means
Exit definitions in helpers may not use action-only properties such as `responseType`, `viewTemplatePath`, or `statusCode`. If any exit of a loaded helper defines one of these, the helpers hook logs this warning identifying the source file, and the offending property is ignored. These features control HTTP responses, which only actions produce.
Source
Thrown at lib/hooks/helpers/private/load-helpers.js:84
'from '+helperDef._loadedFrom+'. This feature can only be used '+
'by actions, not by helpers!'
);
}
var hasAnyConfusingExitProps = (
_.isObject(helperDef.exits) &&
_.any(helperDef.exits, function(exitDef){
return (
_.isObject(exitDef) &&
(
exitDef.responseType !== undefined ||
exitDef.viewTemplatePath !== undefined ||
exitDef.statusCode !== undefined
)
);
})
);
if (hasAnyConfusingExitProps) {
sails.log.warn(
'Ignoring unexpected property in one of the exits of the helper '+
'definition loaded from '+helperDef._loadedFrom+'. Features like '+
'`responseType`, `viewTemplatePath`, and `statusCode` can only be '+
'used by actions, not by helpers!'
);
}
// Build & expose helper on `sails.helpers`
// > e.g. sails.helpers.userHelpers.foo.myHelper
sails.hooks.helpers.furnishHelper(keyPath, helperDef);
} catch (err) {
// If an error occurs building the callable, throw here to bust
// out of the _.each loop early
throw flaverr({
code: 'E_FAILED_TO_BUILD_CALLABLE',
identity: helperDef.identity,
loadedFrom: identity,
raw: errView on GitHub (pinned to 7b76422cc2)
Solutions
- Remove responseType/viewTemplatePath/statusCode from the helper's exit definitions.
- Handle response customization in the calling action: switch on the helper's exits (exits: { badRequest: { responseType: 'badRequest' } } on the action side).
- Keep helper exits plain (description-only) and let actions decide how to respond.
Example fix
// before (helper exits)
exits: { notFound: { responseType: 'notFound', statusCode: 404 } }
// after (helper)
exits: { notFound: { description: 'Record not found.' } }
// ...and in the calling action: exits: { notFound: { responseType: 'notFound' } } Defensive patterns
Strategy: validation
Validate before calling
const actionOnly = ['responseType', 'viewTemplatePath', 'statusCode'];
for (const [name, exit] of Object.entries(helperDef.exits || {})) {
const offending = actionOnly.filter(k => exit[k] !== undefined);
if (offending.length) console.warn(`Exit '${name}' uses action-only props: ${offending}`);
} Prevention
- Keep helper exit definitions to descriptions only.
- Put response customization (statusCode, responseType, views) in the calling action's exits.
- When refactoring actions into helpers, strip HTTP-specific exit properties.
When it happens
Trigger: A helper's exits dictionary includes e.g. exits.badRequest = { responseType: 'badRequest' } or { statusCode: 400 } or { viewTemplatePath: '...' }, detected by hasAnyConfusingExitProps during helper loading.
Common situations: Copy-pasting exit definitions from actions into helpers, assuming helper exits behave like action exits for response negotiation, or migrating legacy response-handling code into helpers.
Related errors
AI-assisted analysis of balderdashy/sails@7b76422cc2 (2026-09-01).
Data as JSON: /api/errors/48dcade906fdae6e.
Report an issue: GitHub.