swagger-api/swagger-ui · error · TypeError
wrapActions needs to return a function that returns a new fu
Error message
wrapActions needs to return a function that returns a new function (ie the wrapped action)
What it means
Swagger UI's plugin system registers action wrappers under statePlugins.<plugin>.wrapActions.<actionName>. Each entry must be a curried higher-order function — (originalAction, getSystem) => (...args) => newValue — so the system can rebuild a callable action. This TypeError is raised in getWrappedAndBoundActions (src/core/system.js:177) during system construction when the rebuilt wrapper is not a function. In practice the guard inspects a locally-built closure, so the same mistake usually surfaces as a downstream 'TypeError: ... is not a function' when the wrapped action is dispatched.
Source
Thrown at src/core/system.js:177
let actionGroups = this.getBoundActions(dispatch)
return objMap(actionGroups, (actions, actionGroupName) => {
let wrappers = this.system.statePlugins[actionGroupName.slice(0,-7)].wrapActions
if(wrappers) {
return objMap(actions, (action, actionName) => {
let wrap = wrappers[actionName]
if(!wrap) {
return action
}
if(!Array.isArray(wrap)) {
wrap = [wrap]
}
return wrap.reduce((acc, fn) => {
let newAction = (...args) => {
return fn(acc, this.getSystem())(...args)
}
if(!isFn(newAction)) {
throw new TypeError("wrapActions needs to return a function that returns a new function (ie the wrapped action)")
}
return wrapWithTryCatch(newAction, this.getSystem)
}, action || Function.prototype)
})
}
return actions
})
}
getWrappedAndBoundSelectors(getState, getSystem) {
let selectorGroups = this.getBoundSelectors(getState, getSystem)
return objMap(selectorGroups, (selectors, selectorGroupName) => {
let stateName = [selectorGroupName.slice(0, -9)] // selectors = 9 chars
let wrappers = this.system.statePlugins[stateName].wrapSelectors
if(wrappers) {
return objMap(selectors, (selector, selectorName) => {
let wrap = wrappers[selectorName]
if(!wrap) {View on GitHub (pinned to 3d9d0916d4)
Solutions
- Reshape each wrapActions entry as two nested arrow functions: (oriAction, system) => (...args) => { ...; return ori(...args) }.
- Confirm the wrapper key exactly matches an existing action name in the same statePlugin (e.g. spec.updateSpec), otherwise the wrap never engages.
- Even if you only need the system and no args, still return (...args) => ori(...args) — the inner function is mandatory.
- Smoke-test the plugin by constructing SwaggerUI({ plugins: [yourPlugin], domNode }) and dispatching the wrapped action to confirm it stays callable.
Example fix
// before
wrapActions: {
updateSpec: (ori, system) => {
console.log("wrapping", system)
}
}
// after
wrapActions: {
updateSpec: (ori, system) => (...args) => {
console.log("wrapping", system)
return ori(...args)
}
} Defensive patterns
Strategy: validation
Validate before calling
// Validate a plugin's wrapActions before registering it.
function validateWrapActions(plugin) {
const groups = (plugin && plugin.statePlugins) || {}
for (const [pluginName, sp] of Object.entries(groups)) {
for (const [name, wrap] of Object.entries(sp.wrapActions || {})) {
const arr = Array.isArray(wrap) ? wrap : [wrap]
arr.forEach((fn, i) => {
if (typeof fn !== "function")
throw new Error(`wrapActions[${pluginName}.${name}][${i}] is not a function`)
const produced = fn(() => {}, {}) // (ori, system)
if (typeof produced !== "function")
throw new Error(`wrapActions[${pluginName}.${name}][${i}] must return a function; got ${typeof produced}`)
})
}
}
return plugin
} Type guard
// Narrows a wrapAction entry to the curried (ori, system) => fn form.
const isWrapAction = (w) => {
const fn = Array.isArray(w) ? w[0] : w
return typeof fn === "function" && typeof fn(() => {}, {}) === "function"
} Try / catch
try {
SwaggerUI({ plugins: [myPlugin], domNode: "#swagger" })
} catch (e) {
if (/wrapActions needs to return a function/.test(e.message)) {
console.error("A wrapActions entry is not curried (needs two arrow functions):", e)
} else {
throw e
}
} Prevention
- Always use the two-arrow shape (ori, system) => (...args) => result for wrapActions.
- Copy a known-good wrapActions block (e.g. src/core/plugins/on-complete/index.js) as your template.
- Run validateWrapActions on custom plugins before passing them to SwaggerUI().
When it happens
Trigger: Defining a wrapActions entry with only one arrow that returns a value, e.g. wrapActions: { updateSpec: (ori, system) => { doSomething() } } (returns undefined) instead of (ori, system) => (...args) => {...}; returning a plain value/object from the outer arrow; assigning a wrapActions key to a function whose outer call does not yield a function.
Common situations: Writing a custom Swagger UI plugin and forgetting the second (inner) arrow function — the most common copy-paste mistake; migrating a plugin from another Redux app and assuming a simpler (ori) => result signature; assigning the wrapper to a key that does not match an existing action name (silently no-ops, leading devs to 'fix' it by changing the signature incorrectly).
Related errors
- wrapSelector needs to return a function that returns a new f
- Need a string, to fetch a component. Was given a ${typeof co
AI-assisted analysis of swagger-api/swagger-ui@3d9d0916d4 (2026-08-13).
Data as JSON: /api/errors/c691d0be10836f27.
Report an issue: GitHub.