Can not apply hooks · Issue #3576 · feathersjs/feathers · GitHub
Skip to content

Can not apply hooks #3576

Open
Open

Description

@EmileSpecs

In the typed client (thus this is browser error) I get the following error:

500
Can not apply hooks. 'report' is not a function

at objectHooks (.../app/node_modules/.pnpm/@feathersjs+hooks@0.9.0/node_modules/@feathersjs/hooks/script/hooks.js:66:19)

Report is a custom function of the users service:
async report(data: ReportData, params: ServiceParams)

I also call some hooks on the custom method, i.e.:

app.service(userPath).hooks({
  before: {
    report: [authorizeHook()]
  }
})

I didn't get this when I used Feathers 5.0.24, so the only thing that changed is that I updated the Feathers API and client to 5.0.33.

The only relevant change I saw in the releases was that the typing for the service methods had changed, so I changed it to:
export const userMethods: Array<keyof UserService> = ['find', 'get', 'create', 'patch', 'remove', 'report']

That made no difference however, I still get the error.

Any ideas?

Activity

  1. EmileSpecs commented on May 12, 2025

    @EmileSpecs
    Author

    Some more details:

    • I've had to remove all custom methods from <service>Methods exports in all *.shared.ts files, all custom methods cause this error if they are included in the exposed methods array.
    • Calling the custom methods in the server or via Postman directly is not an issue, it works as expected.

    So it's an issue with the Feathers client only.

    @daffl / @marshallswain any ideas?
    I've checked the return values of api.service() in the client, and it contains the custom methods so it's not like they are not included in the client.

  2. daffl commented on May 12, 2025

    @daffl
    Member

    Thanks for digging into that. I'm assuming this would be reproducible by adding a custom method to a client service and trying to add hooks to it?

  3. EmileSpecs commented on May 13, 2025

    @EmileSpecs
    Author

    Hi @daffl

    I just created a totally new install using: pnpm create feathers@latest test
    I also added authentication using: npx feathers generate authentication

    I then ONLY added this to the users.class.ts:

    export class UserService<ServiceParams extends Params = UserParams> extends KnexService<
      User,
      UserData,
      UserParams,
      UserPatch
    > {
      async test(data: any, params?: Params) {
        return {
          message: 'Hello World'
        }
      }
    }
    

    users.shared.ts then has userMethods:

    export const userMethods: Array<keyof UserService> = ['find', 'get', 'create', 'patch', 'remove', 'test']
    

    If I remove 'test' from userMethods, build the client and install the client, then there are no errors, it's only when it's added to the userMethods, which of course it must be to be available in the client.

    Then built the client using: pnpm bundle:client
    Installed the client in my app: pnpm add http://localhost:3030/test-0.0.1.tgz

    I don't have any hooks defined for the custom service method (not in the API nor the client app).

    In client I then get this error:

    500
    Can not apply hooks. 'test' is not a function...
    
    at objectHooks (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+hooks@0.9.0/node_modules/@feathersjs/hooks/script/hooks.js:66:19)
    at hooks (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+hooks@0.9.0/node_modules/@feathersjs/hooks/script/index.js:54:43)
    at Feathers.hookMixin (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+feathers@5.0.34/node_modules/@feathersjs/feathers/src/hooks.ts:212:8)
    at  (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+feathers@5.0.34/node_modules/@feathersjs/feathers/src/application.ts:178:36)
    at Feathers.use (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+feathers@5.0.34/node_modules/@feathersjs/feathers/src/application.ts:178:17)
    at Feathers.userClient (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/athlytic-api@http+++localhost+3030+test-0.0.1.tgz_typescript@5.8.3/node_modules/test/lib/services/users/users.shared.js:8:12)
    at Feathers.configure (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/@feathersjs+feathers@5.0.34/node_modules/@feathersjs/feathers/src/application.ts:52:14)
    at createClient (E:/Specs/Development/Athlytic/app/node_modules/.pnpm/athlytic-api@http+++localhost+3030+test-0.0.1.tgz_typescript@5.8.3/node_modules/test/lib/client.js:24:12)
    at E:/Specs/Development/Athlytic/app/plugins/01.feathers.ts:21:64)
    

    In the client plugin I'm just creating the Feathers client:

    const connection = import.meta.server
        ? rest(host).fetch($fetch, OFetch)
        : socketio(io(host, { transports: ['websocket'] }))
    
      // create the feathers client
      const feathersClient = createClient(connection, { storage, storageKey })
    
  4. EmileSpecs commented on May 22, 2025

    @EmileSpecs
    Author

    Hi @daffl

    I have found an interesting clue:

    export const subscriptionMethods: Array<keyof SubscriptionService> = [
      'find',
      'get',
      'create',
      'patch',
      'remove',
      'change'
    ]
    
    export const subscriptionClient = (client: ClientApplication) => {
      const connection = client.get('connection')
    
      console.log('subscriptionClient create:', connection.service(subscriptionPath).create) // logs as Function
      console.log('subscriptionClient change:', connection.service(subscriptionPath).change) // logs as undefined
    
      client.use(subscriptionPath, connection.service(subscriptionPath), {
        methods: subscriptionMethods
      })
    }
    

    Note that the change method does exist in the SubscriptionService class.

    In my client, I have this to create the connection:

    const connection = import.meta.server
        ? rest(host).fetch($fetch, OFetch)
        : socketio(io(host, { transports: ['websocket'] }))
    

    When creating a REST connection, I get the error but when I create a socket connection I do not get the error.

    So it seems to me that this only happens when using REST.

    Hope that helps narrow things down.

  5. daffl commented on May 22, 2025

    @daffl
    Member

    Would this be enough to create a minimal example to reproduce? I wonder if this is happening because of how custom methods are initialised in https://github.com/feathersjs/feathers/blob/dove/packages/rest-client/src/base.ts#L70-L96

  6. laurensiusadi commented on Jan 14, 2026

    @laurensiusadi
    Contributor

    https://github.com/feathersjs/feathers/blob/dove/packages/feathers/src/service.ts#L30-L36

    export function getHookMethods(service: any, options: ServiceOptions) {
      const { methods } = options
    
      return (defaultServiceMethods as any as string[])
        .filter((m) => typeof service[m] === 'function' && !methods.includes(m))
        .concat(methods.filter((m) => typeof service[m] === 'function'))
    }
    

    Adding methods.filter seems to fix it locally for me.

  7. daffl commented on Jan 14, 2026

    @daffl
    Member

    @laurensiusadi That looks like a reasonable change. Want to submit a PR?

  8. daffl commented on Jan 14, 2026

    @daffl
    Member

    Actually, now I'm wondering why it doesn't just throw an error if you are trying to make a method public that doesn't exist on the service.

  9. laurensiusadi commented on Jan 20, 2026

    @laurensiusadi
    Contributor

    I have opened a PR for this @daffl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions