{"record":{"id":"7ab5c642d20e3387","repo":"AlistGo/alist","slug":"get-upload-server-failed-w","errorCode":null,"errorMessage":"get upload server failed: %w","messagePattern":"get upload server failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/darkibox/driver.go","lineNumber":237,"sourceCode":"\t\t}, nil)\n\t}\n\n\tfileCode := fileCodeFromObjID(obj.GetID())\n\treturn d.callAPI(ctx, \"/file/delete\", map[string]string{\n\t\t\"file_code\": fileCode,\n\t}, nil)\n}\n\nfunc (d *Darkibox) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {\n\tfolderID := d.RootFolderID\n\tif dstDir.GetID() != \"\" {\n\t\tfolderID = folderIDFromObjID(dstDir.GetID())\n\t}\n\n\t// Step 1: Get the upload server URL\n\tvar server uploadServerResult\n\tif err := d.callAPI(ctx, \"/upload/server\", nil, &server); err != nil {\n\t\treturn nil, fmt.Errorf(\"get upload server failed: %w\", err)\n\t}\n\tif server.URL == \"\" {\n\t\treturn nil, fmt.Errorf(\"no upload server URL returned\")\n\t}\n\n\t// Step 2: Upload the file to the upload server\n\treader := driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{\n\t\tReader:         file,\n\t\tUpdateProgress: up,\n\t})\n\n\tres, err := base.RestyClient.R().\n\t\tSetContext(ctx).\n\t\tSetMultipartField(\"file\", file.GetName(), \"\", reader).\n\t\tSetMultipartFormData(map[string]string{\n\t\t\t\"key\":    d.APIKey,\n\t\t\t\"fld_id\": fldIDStr(folderID),\n\t\t}).","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/darkibox/driver.go#L219-L255","documentation":"During upload (Put), the Darkibox driver first calls /upload/server to discover which upload endpoint to use. This error means that discovery call failed; the %w chain holds the actual callAPI failure (HTTP, API status, or decode). No bytes were sent.","triggerScenarios":"GET /upload/server returns non-200 HTTP status, provider status != 200 (bad key, maintenance), or the response body's Result field fails to unmarshal into uploadServerResult.","commonSituations":"API key invalid or out of upload quota; provider rotating/disabling upload servers; network proxy stripping query params (the key travels as a query param via callAPI); apiBase domain changed.","solutions":["Read the wrapped error — if it says 'darkibox api error: status=... msg=...', the provider rejected the key/quota; renew the key in the driver config","Retry after confirming the account can upload via the Darkibox web UI","If it is a decode failure, the provider changed the response schema — update uploadServerResult to match the new JSON"],"exampleFix":"// before\nif err := d.callAPI(ctx, \"/upload/server\", nil, &server); err != nil {\n\treturn nil, fmt.Errorf(\"get upload server failed: %w\", err)\n}\n// after — nothing to change at the call site; guard the shape after success too (see 664). Keep this wrap but log server URL on later failure for correlation.","handlingStrategy":"try-catch","validationCode":"if d.APIKey == \"\" {\n\treturn errors.New(\"darkibox API key not configured\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"get upload server failed\") {\n\tif isAuthError(err) {\n\t\treturn promptReconfigureKey()\n\t}\n\treturn backoffRetry(upload, 3)\n}","preventionTips":["Validate the API key with a cheap list call before starting large uploads","Monitor for provider API-base changes"],"tags":["darkibox","upload","api-error","storage-driver"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}