{"record":{"id":"7316a05bed696fb1","repo":"immich-app/immich","slug":"unknown-method-step-method","errorCode":null,"errorMessage":"Unknown method ${step.method}","messagePattern":"Unknown method (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/workflow.service.ts","lineNumber":93,"sourceCode":"      })),\n    );\n\n    return mapWorkflow(workflow);\n  }\n\n  async delete(auth: AuthDto, id: string): Promise<void> {\n    await this.requireAccess({ auth, permission: Permission.WorkflowDelete, ids: [id] });\n    await this.workflowRepository.delete(id);\n  }\n\n  private async resolveAndValidateSteps<T extends { method: string }>(steps: T[], trigger: WorkflowTrigger) {\n    const methods = await this.pluginRepository.getForValidation();\n    const results: Array<T & { pluginMethod: PluginMethodSearchResponse }> = [];\n\n    for (const step of steps) {\n      const pluginMethod = resolveMethod(methods, step.method);\n      if (!pluginMethod) {\n        throw new BadRequestException(`Unknown method ${step.method}`);\n      }\n\n      if (!isMethodCompatible(pluginMethod, trigger)) {\n        throw new BadRequestException(`Method \"${step.method}\" is incompatible with workflow trigger: \"${trigger}\"`);\n      }\n\n      results.push({ ...step, pluginMethod });\n    }\n\n    // TODO make sure all steps can use a common WorkflowType\n\n    return results;\n  }\n\n  private findOrFail(id: string) {\n    return findOrFail(() => this.workflowRepository.get(id), 'Workflow');\n  }\n}","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/workflow.service.ts#L75-L111","documentation":"A BadRequestException (HTTP 400) thrown by WorkflowService.resolveAndValidateSteps when a workflow step's method string cannot be resolved to any loaded plugin method. The method string is parsed via the regex name[@version]#method and matched against pluginRepository.getForValidation(); no match yields this error.","triggerScenarios":"POST/PUT /workflows with a step.method like 'myplugin#doThing' where no enabled plugin named 'myplugin' exposing method 'doThing' is loaded. Also when the method string is malformed (missing '#' separator) so parseMethodString returns undefined.","commonSituations":"Plugin not yet imported or disabled; typo in plugin or method name; version mismatch (method exists in v2 but step references v1); plugin failed to import due to a WASM error; method string format changed.","solutions":["Confirm the plugin is imported and enabled via GET /plugins and that the method is listed.","Correct the method string to the exact 'pluginName[@version]#methodName' format returned by the plugin search endpoint.","Re-import or update the plugin if the expected method is missing.","Match the version segment if the plugin has multiple versions installed."],"exampleFix":"// before\n{ \"method\": \"myplugin#doThin\" } // typo in method name\n\n// after\n{ \"method\": \"myplugin@1.2.0#doThing\" } // exact name and version from /plugins","handlingStrategy":"validation","validationCode":"async function methodExists(methodString) {\n  const methods = await api.listPluginMethods();\n  const parsed = parseMethodString(methodString); // name[@version]#method\n  return methods.some((m) => m.pluginName === parsed?.pluginName && m.name === parsed?.methodName);\n}\nfor (const step of dto.steps) {\n  if (!(await methodExists(step.method))) {\n    return badRequest(`Unknown method ${step.method}`);\n  }\n}","typeGuard":"const isUnknownMethodError = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && (e as any).status === 400 &&\n  typeof (e as any).message === 'string' && (e as any).message.startsWith('Unknown method');","tryCatchPattern":"try {\n  await api.createWorkflow(dto);\n} catch (e) {\n  if (isUnknownMethodError(e)) {\n    setFieldError('steps', e.message);\n    return;\n  }\n  throw e;\n}","preventionTips":["Build the method picker in the UI from live /plugins data so only valid methods are selectable.","Match the exact 'pluginName[@version]#methodName' format.","Re-import the plugin if the expected method is missing."],"tags":["workflow","plugin","validation","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}