{"record":{"id":"71dd48a71bc5944e","repo":"immich-app/immich","slug":"calling-host-functions-is-not-allowed-without-sett","errorCode":null,"errorMessage":"Calling host functions is not allowed without setting methods[].hostFunctions=true in the plugin manifest","messagePattern":"Calling host functions is not allowed without setting methods\\[\\]\\.hostFunctions=true in the plugin manifest","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/workflow-execution.service.ts","lineNumber":33,"sourceCode":"import { PluginManifestDto } from 'src/dtos/plugin-manifest.dto';\nimport {\n  BootstrapEventPriority,\n  DatabaseLock,\n  ImmichEnvironment,\n  ImmichWorker,\n  JobName,\n  JobStatus,\n  QueueName,\n  WorkflowType,\n} from 'src/enum';\nimport { ArgOf } from 'src/repositories/event.repository';\nimport { AlbumService } from 'src/services/album.service';\nimport { AssetService } from 'src/services/asset.service';\nimport { BaseService } from 'src/services/base.service';\nimport { JobOf } from 'src/types';\n\nconst dummy = () => {\n  throw new Error(\n    `Calling host functions is not allowed without setting methods[].hostFunctions=true in the plugin manifest`,\n  );\n};\n\ntype ExecuteOptions<T extends WorkflowType> = {\n  read: (type: T) => Promise<{ authUserId: string; data: WorkflowEventData<T> }>;\n  write: (auth: AuthDto, changes: WorkflowChanges<T>) => Promise<void>;\n};\n\ntype AssetTrigger = { userId: string; assetId: string; trigger: WorkflowTrigger };\n\ntype HostContext = {\n  allowedHosts: string[];\n};\n\nexport class WorkflowExecutionService extends BaseService {\n  private jwtSecret!: string;\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/workflow-execution.service.ts#L15-L51","documentation":"A plain Error (not an HttpException) thrown by the dummy() stub used when a plugin WASM module calls a host function but the plugin was loaded with the stub function set because methods[].hostFunctions was not set to true in its manifest. The plugin loader in onPluginLoad loads plugins twice: once with stubs (hostFunctions=false) and once with real functions (hostFunctions=true); calling a real host function on the stub-loaded instance throws this.","triggerScenarios":"A plugin's WASM code invokes httpRequest, searchAlbums, createAlbum, etc., but the plugin manifest declares the method without hostFunctions=true, so only the stub instance is loaded. The error surfaces inside the Extism plugin call and is caught by the execute() try/catch, failing the workflow run.","commonSituations":"Plugin author forgot to set hostFunctions:true in the manifest for a method that calls host functions; method was refactored to use host functions without updating the manifest; manifest schema drift between SDK and server versions.","solutions":["Edit the plugin's manifest.json and set hostFunctions:true on every method that calls host functions, then re-import the plugin.","Confirm the plugin is being re-imported after the manifest change (restart microservices or change the hash to force re-import).","Ensure the method only needs host functions when truly required; otherwise remove the host function call.","Verify the manifest validates against PluginManifestDto.schema after the edit."],"exampleFix":"// before (manifest.json)\n{ \"methods\": [{ \"name\": \"tagImage\", \"type\": \"asset.v1\" }] }\n\n// after\n{ \"methods\": [{ \"name\": \"tagImage\", \"type\": \"asset.v1\", \"hostFunctions\": true }] }","handlingStrategy":"validation","validationCode":"// Plugin authoring-time validation of the manifest before import\nconst needsHostFunctions = (wasm) => Boolean(wasm.callsHostFunction); // per plugin SDK analysis\nfor (const m of manifest.methods) {\n  if (needsHostFunctions(m) && !m.hostFunctions) {\n    throw new Error(`Method ${m.name} calls host functions but hostFunctions is not true`);\n  }\n}","typeGuard":"const isHostFunctionManifestError = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && typeof (e as any).message === 'string' &&\n  (e as any).message.includes('hostFunctions=true');","tryCatchPattern":"// This error occurs inside the plugin runtime; catch it at the workflow run level\ntry {\n  await runWorkflow(workflowId);\n} catch (e) {\n  if (isHostFunctionManifestError(e)) {\n    logger.error('Plugin manifest missing hostFunctions:true; update manifest and re-import');\n  }\n}","preventionTips":["Set hostFunctions:true on every method that calls host functions in the manifest.","Run plugin manifest validation against PluginManifestDto.schema before import.","Restart microservices or bump the plugin hash to force re-import after manifest edits."],"tags":["workflow","plugin","manifest","extism","host-functions"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}