{"record":{"id":"f3632765fd145228","repo":"immich-app/immich","slug":"this-endpoint-can-only-be-used-with-a-session-toke-f36327","errorCode":null,"errorMessage":"This endpoint can only be used with a session token","messagePattern":"This endpoint can only be used with a session token","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/session.service.ts","lineNumber":32,"sourceCode":"import { BaseService } from 'src/services/base.service.js';\n\n@Injectable()\nexport class SessionService extends BaseService {\n  @OnJob({ name: JobName.SessionCleanup, queue: QueueName.BackgroundTask })\n  async handleCleanup(): Promise<JobStatus> {\n    const sessions = await this.sessionRepository.cleanup();\n    for (const session of sessions) {\n      this.logger.verbose(`Deleted expired session token: ${session.deviceOS}/${session.deviceType}`);\n    }\n\n    this.logger.log(`Deleted ${sessions.length} expired session tokens`);\n\n    return JobStatus.Success;\n  }\n\n  async create(auth: AuthDto, dto: SessionCreateDto): Promise<SessionCreateResponseDto> {\n    if (!auth.session) {\n      throw new BadRequestException('This endpoint can only be used with a session token');\n    }\n\n    const token = this.cryptoRepository.randomBytesAsText(32);\n    const hashed = this.cryptoRepository.hashSha256(token);\n    const session = await this.sessionRepository.create({\n      parentId: auth.session.id,\n      userId: auth.user.id,\n      expiresAt: dto.duration ? DateTime.now().plus({ seconds: dto.duration }).toJSDate() : null,\n      deviceType: dto.deviceType,\n      deviceOS: dto.deviceOS,\n      token: hashed,\n    });\n\n    return { ...mapSession(session), token };\n  }\n\n  async getAll(auth: AuthDto): Promise<SessionResponseDto[]> {\n    const sessions = await this.sessionRepository.getByUserId(auth.user.id);","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/session.service.ts#L14-L50","documentation":"Session.create issues child API keys/sessions but requires the caller to already be authenticated with a session token (auth.session set). Requests authenticated only by an API key have no session, so the endpoint refuses with this BadRequestException.","triggerScenarios":"POST /session (create) with an Authorization header carrying an API key instead of a session cookie/token — auth.session is undefined in the resolved AuthDto.","commonSituations":"Scripts or CI jobs automating session creation using an API key; a user logged in via API key in a client trying to create child sessions; omitting login before calling this endpoint.","solutions":["Authenticate with a session token (log in via web/password flow) before calling this endpoint.","If automating, first perform a login to obtain a session cookie, then call the endpoint.","Use the API key only for endpoints that permit key-based auth; create the session interactively."],"exampleFix":"// before\nawait api.createSession(apiKeyAuth); // API key -> no session\n// after\nconst session = await login(email, password); // yields session token\nawait api.createSession(sessionAuth);","handlingStrategy":"validation","validationCode":"function canCreateSession(auth) {\n  return Boolean(auth && auth.session && auth.session.id);\n}\nif (!canCreateSession(auth)) {\n  throw new Error('Session creation requires session-token auth, not an API key');\n}","typeGuard":"const hasSession = (auth) =>\n  typeof auth === 'object' && auth !== null && 'session' in auth && auth.session != null;","tryCatchPattern":"try {\n  await api.createSession(dto);\n} catch (e) {\n  if (e.status === 400 && /session token/.test(e.message)) {\n    await loginWithPassword(); // obtain a session, then retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Log in with credentials before calling session endpoints.","Do not use API keys for interactive session flows.","Check auth kind in client code before hitting session APIs."],"tags":["session","authentication","bad-request","api"],"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"}