{"record":{"id":"412cc5d8e0235d5e","repo":"AlistGo/alist","slug":"result-is-null","errorCode":null,"errorMessage":"result is null","messagePattern":"result is null","errorType":"exception","errorClass":"ErrNullResult","httpStatus":null,"severity":"error","filePath":"pkg/aria2/rpc/json2.go","lineNumber":100,"sourceCode":"\tvar c clientResponse\n\tif err := json.NewDecoder(r).Decode(&c); err != nil {\n\t\treturn err\n\t}\n\treturn c.decode(reply)\n}\n\ntype ErrorCode int\n\nconst (\n\tE_PARSE       ErrorCode = -32700\n\tE_INVALID_REQ ErrorCode = -32600\n\tE_NO_METHOD   ErrorCode = -32601\n\tE_BAD_PARAMS  ErrorCode = -32602\n\tE_INTERNAL    ErrorCode = -32603\n\tE_SERVER      ErrorCode = -32000\n)\n\nvar ErrNullResult = errors.New(\"result is null\")\n\ntype Error struct {\n\t// A Number that indicates the error type that occurred.\n\tCode ErrorCode `json:\"code\"` /* required */\n\n\t// A String providing a short description of the error.\n\t// The message SHOULD be limited to a concise single sentence.\n\tMessage string `json:\"message\"` /* required */\n\n\t// A Primitive or Structured value that contains additional information about the error.\n\tData interface{} `json:\"data\"` /* optional */\n}\n\nfunc (e *Error) Error() string {\n\treturn e.Message\n}\n","sourceCodeStart":82,"sourceCodeEnd":117,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/pkg/aria2/rpc/json2.go#L82-L117","documentation":"ErrNullResult is returned by clientResponse.decode when a JSON-RPC response carries no error but its result field is null/absent. The client treats a null result as protocol failure rather than a legitimate empty value, because every aria2 method it wraps is expected to return something (a gid, a struct, an array).","triggerScenarios":"Any rpc.Client call whose daemon reply has \"result\": null — commonly an expired or invalid GID passed to TellStatus/ChangeOption, or a non-conforming aria2-compatible daemon (AriaNg-adjacent wrappers, some forks) returning null for empty lists.","commonSituations":"Polling a download status after aria2 restarted and lost its task table (GIDs no longer valid); using a third-party JSON-RPC endpoint that returns null instead of [] or \"\"; version drift where a method's reply shape changed.","solutions":["Verify the GID is still valid (list downloads and match) before operating on it","If the aria2 daemon restarted, re-add the download rather than polling the stale GID","If the endpoint is a non-aria2 JSON-RPC server, wrap calls to tolerate null results or switch to a real aria2 daemon"],"exampleFix":"// before\nst, err := c.TellStatus(gid)\n// after: tolerate tasks lost after a daemon restart\nst, err := c.TellStatus(gid)\nif err == rpc.ErrNullResult {\n    // gid no longer known to aria2; re-add or drop the task\n    gid, err = c.AddURI([]string{url}, opts)\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"func isNullResult(err error) bool {\n    return errors.Is(err, rpc.ErrNullResult)\n}","tryCatchPattern":"st, err := c.TellStatus(gid)\nif err != nil {\n    if errors.Is(err, rpc.ErrNullResult) {\n        // gid unknown to daemon (expired/restarted): re-add or drop\n        gid, err = c.AddURI([]string{taskUrl}, nil)\n    }\n    // handle other errors\n}","preventionTips":["Detect aria2 daemon restarts (connection drops) and invalidate cached GIDs","Compare GIDs against the live download list after daemon restarts","Use errors.Is with the exported rpc.ErrNullResult sentinel rather than string matching"],"tags":["aria2","json-rpc","null-result"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}