{"record":{"id":"26c34f5cef2fea00","repo":"AlistGo/alist","slug":"ticket-is-required","errorCode":null,"errorMessage":"ticket is required","messagePattern":"ticket is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"drivers/lark/other.go","lineNumber":188,"sourceCode":"\t\tType:    docType,\n\t\tFormats: larkExportOptions(docType),\n\t}\n\tswitch docType {\n\tcase larkdrive.TypeSheet:\n\t\tout.SubResources, err = c.listSheetSubResources(ctx, token)\n\tcase larkdrive.TypeBitable:\n\t\tout.SubResources, err = c.listBitableSubResources(ctx, token)\n\t}\n\tif err != nil {\n\t\tout.SubResourceError = err.Error()\n\t}\n\treturn out, nil\n}\n\nfunc (c *Lark) getExportTask(ctx context.Context, obj model.Obj, req larkExportStatusReq) (*LarkExportStatusResp, error) {\n\tticket := strings.TrimSpace(req.Ticket)\n\tif ticket == \"\" {\n\t\treturn nil, errors.New(\"ticket is required\")\n\t}\n\ttoken, ok := c.getObjToken(ctx, obj.GetPath())\n\tif !ok {\n\t\treturn nil, errors.WithStack(errors.New(\"lark file token not found\"))\n\t}\n\tresp, err := doDrive(ctx, c, func(opts ...larkcore.RequestOptionFunc) (*larkdrive.GetExportTaskResp, error) {\n\t\treturn c.client.Drive.V1.ExportTask.Get(ctx,\n\t\t\tlarkdrive.NewGetExportTaskReqBuilder().Ticket(ticket).Token(token).Build(), opts...)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !resp.Success() {\n\t\treturn nil, larkAPIError(resp)\n\t}\n\tif resp.Data == nil || resp.Data.Result == nil {\n\t\treturn nil, errors.New(\"lark export task response missing result\")\n\t}","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/lark/other.go#L170-L206","documentation":"getExportTask requires the ticket returned by createExportTask to poll export status (ExportTask.Get with Ticket+Token). A blank ticket after trimming means the status request is malformed by construction, so the driver rejects it before touching the API. Pure request-validation on the export status payload.","triggerScenarios":"larkExportStatusReq submitted with an empty/whitespace ticket field — client lost the ticket from the create step, JSON field name mismatch when hand-crafting the request, or the create response was never persisted.","commonSituations":"Frontend form for export status not carrying the ticket through; API consumer serializing the field with the wrong key; stateless caller that skipped the create step.","solutions":["Always obtain the ticket from createExportTask's response and pass it verbatim to the status call","Validate req.Ticket is non-blank client-side before submitting","Check the JSON field name/case matches larkExportStatusReq's tags"],"exampleFix":"// before\nresp, err := c.getExportTask(ctx, obj, larkExportStatusReq{})\n// after\nif strings.TrimSpace(createResp.Ticket) == \"\" {\n\treturn errors.New(\"export create returned no ticket\")\n}\nresp, err := c.getExportTask(ctx, obj, larkExportStatusReq{Ticket: createResp.Ticket})","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(req.Ticket) == \"\" {\n\treturn errors.New(\"export status requires the ticket from createExportTask\")\n}","typeGuard":"func hasExportTicket(req larkExportStatusReq) bool {\n\treturn strings.TrimSpace(req.Ticket) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Thread the create response's ticket through the whole export flow; never hand-build status requests","Validate required request fields at the API boundary before calling driver methods"],"tags":["lark","feishu","export","validation","driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}