{"record":{"id":"2bca211e652cc2fe","repo":"immich-app/immich","slug":"missing-jwt-token","errorCode":null,"errorMessage":"Missing JWT Token","messagePattern":"Missing JWT Token","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server/src/maintenance/maintenance-worker.service.ts","lineNumber":262,"sourceCode":"    return this.login(jwtToken);\n  }\n\n  async status(potentiallyJwt?: string): Promise<MaintenanceStatusResponseDto> {\n    try {\n      await this.login(potentiallyJwt);\n      return this.getStatus();\n    } catch {\n      return this.getPublicStatus();\n    }\n  }\n\n  detectPriorInstall(): Promise<MaintenanceDetectInstallResponseDto> {\n    return detectPriorInstall(this.storageRepository);\n  }\n\n  async login(jwt?: string): Promise<MaintenanceAuthDto> {\n    if (!jwt) {\n      throw new UnauthorizedException('Missing JWT Token');\n    }\n\n    try {\n      const result = await jwtVerify<MaintenanceAuthDto>(jwt, new TextEncoder().encode(this.secret));\n      return result.payload;\n    } catch {\n      throw new UnauthorizedException('Invalid JWT Token');\n    }\n  }\n\n  async setAction(action: SetMaintenanceModeDto) {\n    this.setStatus({\n      active: true,\n      action: action.action,\n    });\n\n    await this.runAction(action);\n  }","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/maintenance/maintenance-worker.service.ts#L244-L280","documentation":"The maintenance worker's login() method requires a maintenance JWT string; if the argument is absent or empty it throws UnauthorizedException('Missing JWT Token') before any verification is attempted. It is the guard clause distinguishing 'no token supplied' from the separate 'Invalid JWT Token' failure in the jwtVerify catch block.","triggerScenarios":"Calling maintenanceWorkerService.login() (directly or via the authenticate/status callers) with jwt === undefined or an empty string; sending a maintenance login request with no Authorization header / no token parameter so no JWT is passed through.","commonSituations":"Client forgot to attach the maintenance token obtained from a prior login; header stripped by a reverse proxy; calling the status/authenticate path before ever performing a maintenance login; passing the wrong field name so the token never reaches the handler.","solutions":["Perform a maintenance login first and pass the returned token into login()/authenticate.","Attach the JWT in the request (Authorization: Bearer <token> or the maintenance cookie) before calling protected maintenance endpoints.","Check proxy/middleware configuration so the Authorization header is forwarded to Immich.","Confirm the client sends the correct field the controller reads (e.g. token in MaintenanceLoginDto body), not a missing/renamed property."],"exampleFix":"// before\nawait maintenanceWorker.login(); // UnauthorizedException: Missing JWT Token\n// after\nif (!jwt) throw new Error('Login first to obtain a maintenance token');\nawait maintenanceWorker.login(jwt);","handlingStrategy":"validation","validationCode":"if (typeof jwt !== 'string' || jwt.length === 0) {\n  throw new Error('A maintenance JWT is required; perform a maintenance login first');\n}","typeGuard":"function hasJwt(t: string | undefined | null): t is string {\n  return typeof t === 'string' && t.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Always complete a maintenance login to obtain a token before calling authenticate/status.","Send the token via the Authorization header or maintenance cookie and verify proxies forward it.","Check client code sends the exact field the controller expects.","Alert users when no maintenance session exists instead of firing blind requests."],"tags":["jwt","authentication","unauthorized","maintenance"],"backgroundTag":"authentication-required","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}