AlistGo/alist · error
failed get torrent ID
Error message
failed get torrent ID
What it means
After TorrentAdd() succeeds at the RPC level, the tool requires torrent.ID to be non-nil to build its GID. transmission-daemon's torrent-add response (and especially the torrent-duplicate response when the torrent already exists) does not always include the id field, leaving ID nil even though the torrent exists. The tool then fails with this bare error.
Source
Thrown at internal/offline_download/transmission/client.go:115
}
// Flush last bytes
if err = encoder.Close(); err != nil {
return "", errors.Wrap(err, "can't flush last bytes of the base64 encoder")
}
// Get the string form
b64 := buffer.String()
rpcPayload.MetaInfo = &b64
} else { // magnet uri
rpcPayload.Filename = &args.Url
}
torrent, err := t.client.TorrentAdd(context.TODO(), rpcPayload)
if err != nil {
return "", err
}
if torrent.ID == nil {
return "", fmt.Errorf("failed get torrent ID")
}
gid := strconv.FormatInt(*torrent.ID, 10)
return gid, nil
}
func (t *Transmission) Remove(task *tool.DownloadTask) error {
gid, err := strconv.ParseInt(task.GID, 10, 64)
if err != nil {
return err
}
err = t.client.TorrentRemove(context.TODO(), transmissionrpc.TorrentRemovePayload{
IDs: []int64{gid},
DeleteLocalData: false,
})
return err
}
func (t *Transmission) Status(task *tool.DownloadTask) (*tool.Status, error) {View on GitHub (pinned to 843d9dc814)
Solutions
- Check whether the torrent already exists (by hash) before adding, and reuse its id
- If already added, query TorrentGetAllFor / get by hash to obtain the real id
- Upgrade the transmissionrpc library — newer versions normalize the duplicate response
- As a workaround, remove the duplicate torrent first, then re-add
Example fix
// before
if torrent.ID == nil {
return "", fmt.Errorf("failed get torrent ID")
}
// after: fall back to hash lookup for the duplicate case
if torrent.ID == nil && torrent.HashString != nil {
infos, err := t.client.TorrentGetAllFor(ctx, nil)
if err == nil {
for _, i := range infos {
if i.HashString != nil && *i.HashString == *torrent.HashString {
return strconv.FormatInt(*i.ID, 10), nil
}
}
}
}
if torrent.ID == nil {
return "", fmt.Errorf("failed get torrent ID")
} Defensive patterns
Strategy: validation
Validate before calling
torrent, err := t.client.TorrentAdd(context.TODO(), rpcPayload)
if err != nil {
return "", err
}
if torrent.ID == nil {
// likely a duplicate: resolve the existing torrent by hash instead of failing
if torrent.HashString != nil {
if infos, ierr := t.client.TorrentGetAllFor(context.TODO(), nil); ierr == nil {
for _, i := range infos {
if i.HashString != nil && *i.HashString == *torrent.HashString && i.ID != nil {
return strconv.FormatInt(*i.ID, 10), nil
}
}
}
}
return "", fmt.Errorf("failed get torrent ID")
} Type guard
func hasTorrentID(t *transmissionrpc.Torrent) bool {
return t != nil && t.ID != nil
} Try / catch
gid, err := t.AddURL(args)
if err != nil && strings.Contains(err.Error(), "failed get torrent ID") {
// torrent probably already exists: ask the user or dedupe by hash
return errorWithHint(err, "torrent may already exist in transmission; remove it or reuse its id")
} Prevention
- Check for an existing torrent by hash before calling TorrentAdd
- Never blind-retry TorrentAdd on this error — it deepens the duplicate
- Keep the transmissionrpc library current so duplicate responses are normalized
When it happens
Trigger: Adding a torrent/magnet that already exists in transmission (daemon returns 'torrent-duplicate' with only hash/name); a daemon or RPC edge case where the add response omits the id field.
Common situations: Re-adding the same magnet after a partial failure; retry logic that re-submits an existing torrent; seed-existing setups where the torrent is already loaded.
Related errors
- label name is exists
- remote transmission RPC version (v%d) is incompatible with t
- failed get status, wrong gid: %s
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/bdfb38a0eacddfce.
Report an issue: GitHub.