{"record":{"id":"d1af2211337d7f2b","repo":"NickeManarin/ScreenToGif","slug":"unknown-error","errorCode":null,"errorMessage":"Unknown error","messagePattern":"Unknown error","errorType":"exception","errorClass":"UploadException","httpStatus":null,"severity":"error","filePath":"ScreenToGif/Cloud/YandexDisk.cs","lineNumber":29,"sourceCode":"using ScreenToGif.Util.Settings;\nusing ScreenToGif.ViewModel.UploadPresets.History;\nusing ScreenToGif.ViewModel.UploadPresets.Yandex;\n\nnamespace ScreenToGif.Cloud;\n\npublic class YandexDisk : IUploader\n{\n    public async Task<IHistory> UploadFileAsync(IUploadPreset preset, string path, CancellationToken cancellationToken, IProgress<double> progressCallback = null)\n    {\n        if (string.IsNullOrEmpty(path)) \n            throw new ArgumentException(nameof(path));\n\n        var fileName = Path.GetFileName(path);\n\n        var link = await GetAsync<Link>(preset as YandexPreset, \"https://cloud-api.yandex.net/v1/disk/resources/upload?path=app:/\" + fileName + \"&overwrite=true\", cancellationToken);\n            \n        if (string.IsNullOrEmpty(link?.Href)) \n            throw new UploadException(\"Unknown error\");\n\n        await using (var fileSteram = new FileStream(path, FileMode.Open, FileAccess.Read))\n        {\n            await PutAsync(preset as YandexPreset, link.Href, new StreamContent(fileSteram), cancellationToken);\n        }\n\n        var downloadLink = await GetAsync<Link>(preset as YandexPreset, \"https://cloud-api.yandex.net/v1/disk/resources/download?path=app:/\" + fileName, cancellationToken);\n\n        var history = new History\n        {\n            Type = preset.Type,\n            PresetName = preset.Title,\n            DateInUtc = DateTime.UtcNow,\n            Result = 200,\n            Link = downloadLink.Href\n        };\n            \n        return history;","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/NickeManarin/ScreenToGif/blob/a4d0a67c2131cd048ceec86cd40afc2f1a06f2fd/ScreenToGif/Cloud/YandexDisk.cs#L11-L47","documentation":"YandexDisk.UploadFileAsync requests an upload URL from cloud-api.yandex.net/v1/disk/resources/upload and expects a Link object with a non-empty Href. If Href is null/empty, it throws a generic UploadException(\"Unknown error\"). Note: real API errors are caught separately inside GetAsync (error 24), so reaching this line means Yandex returned a parseable but Href-less response body.","triggerScenarios":"GetAsync<Link> succeeds (no ErrorDescriptor.Error) but the deserialized Link.Href is null or empty string. Happens when the JSON shape changed, a required field was renamed, or the response was an unexpected success-shaped payload.","commonSituations":"Yandex API version drift (field renamed from href to something else); malformed filename producing a degenerate response; proxy returning a 200 with an HTML interstitial that deserialized to an empty object;OAuth token valid but app folder not provisioned yet.","solutions":["Re-authorize the Yandex account to refresh preset.OAuthToken.","Log the raw responseBody inside GetAsync when Link.Href is empty so the actual payload can be inspected.","Sanitize the file name (strip characters illegal for Yandex paths) before building the upload URL.","If it persists, treat it as an API contract change and update the Link DTO to match Yandex's current schema."],"exampleFix":"// before\nif (string.IsNullOrEmpty(link?.Href)) \n    throw new UploadException(\"Unknown error\");\n\n// after\nif (string.IsNullOrEmpty(link?.Href)) \n    throw new UploadException($\"Unknown error: Yandex returned no upload Href for file '{fileName}'. Re-authorize the Yandex account.\");","handlingStrategy":"validation","validationCode":"// Sanity-check the parsed upload link before throwing\nif (string.IsNullOrEmpty(link?.Href))\n{\n    LogWriter.Log($\"Yandex upload-URL response missing Href. Token valid: {!string.IsNullOrWhiteSpace((preset as YandexPreset)?.OAuthToken)}\");\n}","typeGuard":"bool HasYandexUploadHref(Link l) => !string.IsNullOrWhiteSpace(l?.Href);","tryCatchPattern":"try { var link = await GetAsync<Link>(...); }\ncatch (UploadException ex) { LogWriter.Log(ex, \"Yandex upload URL\"); throw; }","preventionTips":["Sanitize the file name before building the Yandex URL (no slashes, no illegal chars).","Re-authorize Yandex periodically; stale tokens produce degenerate responses.","Log the raw response body when Href is missing to catch schema drift early."],"tags":["yandex-disk","cloud-upload","network","deserialization"],"backgroundTag":null,"analyzedSha":"a4d0a67c2131cd048ceec86cd40afc2f1a06f2fd","analyzedAt":"2026-08-13T11:12:06.147Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}