{"record":{"id":"837c7ec5fdacc597","repo":"GopeedLab/gopeed","slug":"promise-rejected-837c7e","errorCode":null,"errorMessage":"promise rejected","messagePattern":"promise rejected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/engine/inject/stream/module.go","lineNumber":539,"sourceCode":"\t\t\t\t})\n\t\t\t\tif _, err := thenFn(value, onFulfilled, onRejected); err != nil {\n\t\t\t\t\tsend(nil, err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tsend(value, nil)\n\t})\n\tif !ok {\n\t\treturn nil, errors.New(\"engine loop terminated\")\n\t}\n\tres := <-ch\n\treturn res.value, res.err\n}\n\nfunc exportJSError(value goja.Value) error {\n\tif value == nil || goja.IsUndefined(value) || goja.IsNull(value) {\n\t\treturn errors.New(\"promise rejected\")\n\t}\n\tif err, ok := value.Export().(error); ok {\n\t\treturn err\n\t}\n\tstack := value.String()\n\tif ro, ok := value.(*goja.Object); ok {\n\t\tstackVal := ro.Get(\"stack\")\n\t\tif stackVal != nil && stackVal.String() != \"\" {\n\t\t\tstack = stackVal.String()\n\t\t}\n\t}\n\treturn errors.New(stack)\n}\n\ntype fetchRegistry struct {\n\tmu      sync.Mutex\n\tstreams map[string]*fetchStream\n\tctx     context.Context","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/engine/inject/stream/module.go#L521-L557","documentation":"exportJSError in the stream module (pkg/download/engine/inject/stream/module.go:537-539) is the same conversion helper as the engine's: a promise rejection value of undefined/null, or a nil goja.Value, cannot yield a message, so the error degrades to the generic 'promise rejected'. Any Error object, string, or exported error would have produced a specific message instead.","triggerScenarios":"Stream-related script code rejects with no argument (reject()) or throws undefined/null (common in minified bundles); a fetch/stream polyfill signaling failure with reject(undefined); rejection callbacks invoked with zero arguments.","commonSituations":"Third-party resolver scripts with bare undefined throws; debugging dead-ends because the message carries no cause — it strictly means 'rejected without a reason value'.","solutions":["Instrument the script: wrap stream calls with .catch(e => { throw (e === undefined ? new Error('stream rejected without reason') : e })","Fix scripts to reject with Error objects: reject(new Error('stream aborted'))","Enable any script-side logging the engine provides to capture the failure site","Address the root cause once a real message is recoverable"],"exampleFix":"// before (script)\nstream.open(u).then(null, () => reject())\n\n// after (script)\nstream.open(u).then(null, (e) => reject(e instanceof Error ? e : new Error('stream open failed: ' + String(e))))","handlingStrategy":"try-catch","validationCode":"// Script-side: normalize rejections before they cross into Go\n// .catch(e => { throw e == null ? new Error('stream rejected without reason') : e })","typeGuard":"// Script-side guard:\nfunction norm(e) { return e == null ? new Error('rejected without reason') : e }","tryCatchPattern":"if err != nil && err.Error() == \"promise rejected\" {\n    // stream rejection had no reason value: add script-side catch logging to find the cause\n}","preventionTips":["Reject with Error objects in all stream script code","Wrap polyfill rejections so undefined becomes a descriptive Error","Treat the bare message as a diagnostics gap, not a root cause"],"tags":["javascript","promise","stream","diagnostics"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}