Skip to content

modify action non-functional #287

@Trevortds

Description

@Trevortds

I feel like I'm going a little crazy and must be doing something wrong, because I thought I saw this working before, but now there's nothing.

In short, I can't modify anything through the command line tool. The modify action sends two basically empty POST requests. One to /api/v1/sync, the other to /.

In the following example, I have one overdue task titled "Test task". I want to change its name to "changed content" and postpone it until tomorrow.

trevo@tulkas:~$ todoist --version
todoist version 0.23.0
trevo@tulkas:~$ date
Sun Feb  8 18:35:05 CST 2026
trevo@tulkas:~$ todoist list -f "overdue"
6fx8fw3jv7jw7cXc p4 26/02/07(Sat) 00:00 #Inbox  Test task
trevo@tulkas:~$ todoist --debug modify 6fx8fw3jv7jw7cXc -c "changed content" -d "tomorrow"
2026/02/08 18:35:15 doAPi: called
2026/02/08 18:35:15 config: &todoist.Config{AccessToken:"[token]", DebugMode:true, Color:false, DateFormat:"", DateTimeFormat:""}
2026/02/08 18:35:15 request: &http.Request{Method:"POST", URL:(*url.URL)(0xc0001d46c0), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Authorization":[]string{"Bearer [token]"}, "Content-Type":[]string{"application/x-www-form-urlencoded"}}, Body:io.nopCloserWriterTo{Reader:(*strings.Reader)(0xc00025ebc0)}, GetBody:(func() (io.ReadCloser, error))(0x6acf40), ContentLength:417, TransferEncoding:[]string(nil), Close:false, Host:"api.todoist.com", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), Pattern:"", ctx:context.backgroundCtx{emptyCtx:context.emptyCtx{}}, pat:(*http.pattern)(nil), matches:[]string(nil), otherValues:map[string]string(nil)}
2026/02/08 18:35:15 request.URL: &url.URL{Scheme:"https", Opaque:"", User:(*url.Userinfo)(nil), Host:"api.todoist.com", Path:"/api/v1/sync", RawPath:"", OmitHost:false, ForceQuery:false, RawQuery:"", Fragment:"", RawFragment:""}
2026/02/08 18:35:15 params: &strings.Reader{s:"commands=%5B%7B%22args%22%3A%7B%22due%22%3A%7B%22date%22%3A%22%22%2C%22timezone%22%3A%22%22%2C%22is_recurring%22%3Afalse%2C%22string%22%3A%22%22%2C%22lang%22%3A%22%22%7D%2C%22id%22%3A%226fx8fw3jv7jw7cXc%22%2C%22labels%22%3A%5B%22%22%5D%2C%22priority%22%3A1%7D%2C%22temp_id%22%3A%2221bf2b7f-246a-48bf-a178-8aa2b329e5d6%22%2C%22type%22%3A%22item_update%22%2C%22uuid%22%3A%22314518ba-8dc8-45f1-b0a0-9d896de99905%22%7D%5D", i:0, prevRune:-1}
2026/02/08 18:35:16 response: &http.Response{Status:"200 OK", StatusCode:200, Proto:"HTTP/2.0", ProtoMajor:2, ProtoMinor:0, Header:http.Header{"Alt-Svc":[]string{"h3=\":443\"; ma=86400"}, "Cache-Control":[]string{"no-cache"}, "Content-Length":[]string{"271"}, "Content-Type":[]string{"application/json"}, "Date":[]string{"Mon, 09 Feb 2026 00:35:15 GMT"}, "Referrer-Policy":[]string{"strict-origin-when-cross-origin"}, "Server":[]string{"gunicorn"}, "Set-Cookie":[]string{"csrf=960b83dde2ee4905be0dc68379118866; Expires=Thu, 07-Feb-2036 00:35:15 GMT; Secure; Path=/; SameSite=None", "tduser=v4.public.[userid]; Domain=.todoist.com; Expires=Mon, 23-Feb-2026 00:35:15 GMT; Max-Age=1209600; Secure; HttpOnly; Path=/", "todoistd=\"/CUdA09psYiwY7pwgn9sRGC/RQQ=?\"; Domain=.todoist.com; Expires=Tue, 09-Feb-2027 00:35:15 GMT; Max-Age=31536000; Secure; HttpOnly; Path=/; SameSite=None"}, "Strict-Transport-Security":[]string{"max-age=31536000; includeSubDomains; preload"}, "Vary":[]string{"Accept-Encoding"}, "Via":[]string{"1.1 180a4e1c2aa6a4d95dc2a1b2b749e54a.cloudfront.net (CloudFront)"}, "X-Amz-Cf-Id":[]string{"8QzVSmyoHHr64V5z7OZChzsomKnOOJMum9r0GyZQyS_HvOxvP6gFtQ=="}, "X-Amz-Cf-Pop":[]string{"ORD56-P14"}, "X-Cache":[]string{"Miss from cloudfront"}}, Body:http.http2transportResponseBody{cs:(*http.http2clientStream)(0xc0000d4180)}, ContentLength:271, TransferEncoding:[]string(nil), Close:false, Uncompressed:false, Trailer:http.Header(nil), Request:(*http.Request)(0xc0001fd2c0), TLS:(*tls.ConnectionState)(0xc00045b5c0)}
2026/02/08 18:35:16 doAPi: called
2026/02/08 18:35:16 config: &todoist.Config{AccessToken:"[token]", DebugMode:true, Color:false, DateFormat:"", DateTimeFormat:""}
2026/02/08 18:35:16 request: &http.Request{Method:"POST", URL:(*url.URL)(0xc0001d4c60), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Authorization":[]string{"Bearer [token]"}, "Content-Type":[]string{"application/x-www-form-urlencoded"}}, Body:io.nopCloserWriterTo{Reader:(*strings.Reader)(0xc0002ad100)}, GetBody:(func() (io.ReadCloser, error))(0x6acf40), ContentLength:252, TransferEncoding:[]string(nil), Close:false, Host:"api.todoist.com", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), Pattern:"", ctx:context.backgroundCtx{emptyCtx:context.emptyCtx{}}, pat:(*http.pattern)(nil), matches:[]string(nil), otherValues:map[string]string(nil)}
2026/02/08 18:35:16 request.URL: &url.URL{Scheme:"https", Opaque:"", User:(*url.Userinfo)(nil), Host:"api.todoist.com", Path:"/api/v1/sync", RawPath:"", OmitHost:false, ForceQuery:false, RawQuery:"", Fragment:"", RawFragment:""}
2026/02/08 18:35:16 params: &strings.Reader{s:"commands=%5B%7B%22args%22%3A%7B%22id%22%3A%226fx8fw3jv7jw7cXc%22%2C%22project_id%22%3A%220%22%7D%2C%22temp_id%22%3A%224734a008-a3fe-48e7-915f-755625e156db%22%2C%22type%22%3A%22item_move%22%2C%22uuid%22%3A%22591ebebd-850a-4045-960d-ef495e3db5cd%22%7D%5D", i:0, prevRune:-1}
2026/02/08 18:35:16 response: &http.Response{Status:"200 OK", StatusCode:200, Proto:"HTTP/2.0", ProtoMajor:2, ProtoMinor:0, Header:http.Header{"Alt-Svc":[]string{"h3=\":443\"; ma=86400"}, "Cache-Control":[]string{"no-cache"}, "Content-Length":[]string{"884"}, "Content-Type":[]string{"application/json"}, "Date":[]string{"Mon, 09 Feb 2026 00:35:16 GMT"}, "Referrer-Policy":[]string{"strict-origin-when-cross-origin"}, "Server":[]string{"gunicorn"}, "Set-Cookie":[]string{"csrf=52cdea99da3e4fa4bc8fbef8194c717a; Expires=Thu, 07-Feb-2036 00:35:15 GMT; Secure; Path=/; SameSite=None", "tduser=v4.public.[userid]; Domain=.todoist.com; Expires=Mon, 23-Feb-2026 00:35:16 GMT; Max-Age=1209600; Secure; HttpOnly; Path=/", "todoistd=\"/CUdA09psYiwY7pwgn9sRGC/RQQ=?\"; Domain=.todoist.com; Expires=Tue, 09-Feb-2027 00:35:16 GMT; Max-Age=31536000; Secure; HttpOnly; Path=/; SameSite=None"}, "Strict-Transport-Security":[]string{"max-age=31536000; includeSubDomains; preload"}, "Vary":[]string{"Accept-Encoding"}, "Via":[]string{"1.1 180a4e1c2aa6a4d95dc2a1b2b749e54a.cloudfront.net (CloudFront)"}, "X-Amz-Cf-Id":[]string{"QtVUtA2XpAZs0jSy3jRgBBgt1TwTC13YhgHAtvIgM3OHWBqUXkFpyA=="}, "X-Amz-Cf-Pop":[]string{"ORD56-P14"}, "X-Cache":[]string{"Miss from cloudfront"}}, Body:http.http2transportResponseBody{cs:(*http.http2clientStream)(0xc0000d4300)}, ContentLength:884, TransferEncoding:[]string(nil), Close:false, Uncompressed:false, Trailer:http.Header(nil), Request:(*http.Request)(0xc0004b7a40), TLS:(*tls.ConnectionState)(0xc00045b5c0)}
2026/02/08 18:35:16 doAPi: called
2026/02/08 18:35:16 config: &todoist.Config{AccessToken:"[token]", DebugMode:true, Color:false, DateFormat:"", DateTimeFormat:""}
2026/02/08 18:35:16 request: &http.Request{Method:"POST", URL:(*url.URL)(0xc0001d4f30), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Authorization":[]string{"Bearer [token]"}, "Content-Type":[]string{"application/x-www-form-urlencoded"}}, Body:io.nopCloserWriterTo{Reader:(*strings.Reader)(0xc0002ad240)}, GetBody:(func() (io.ReadCloser, error))(0x6acf40), ContentLength:45, TransferEncoding:[]string(nil), Close:false, Host:"api.todoist.com", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), Pattern:"", ctx:context.backgroundCtx{emptyCtx:context.emptyCtx{}}, pat:(*http.pattern)(nil), matches:[]string(nil), otherValues:map[string]string(nil)}
2026/02/08 18:35:16 request.URL: &url.URL{Scheme:"https", Opaque:"", User:(*url.Userinfo)(nil), Host:"api.todoist.com", Path:"/api/v1/sync", RawPath:"", OmitHost:false, ForceQuery:false, RawQuery:"", Fragment:"", RawFragment:""}
2026/02/08 18:35:16 params: &strings.Reader{s:"resource_types=%5B%22all%22%5D&sync_token=%2A", i:0, prevRune:-1}
2026/02/08 18:35:17 response: &http.Response{Status:"200 OK", StatusCode:200, Proto:"HTTP/2.0", ProtoMajor:2, ProtoMinor:0, Header:http.Header{"Alt-Svc":[]string{"h3=\":443\"; ma=86400"}, "Cache-Control":[]string{"no-cache"}, "Content-Type":[]string{"application/json"}, "Date":[]string{"Mon, 09 Feb 2026 00:35:17 GMT"}, "Referrer-Policy":[]string{"strict-origin-when-cross-origin"}, "Server":[]string{"gunicorn"}, "Set-Cookie":[]string{"csrf=783e81f190094ad0a4fa6138e0bf15e6; Expires=Thu, 07-Feb-2036 00:35:16 GMT; Secure; Path=/; SameSite=None", "tduser=v4.public.[token?idk looked like something not to share]; Domain=.todoist.com; Expires=Mon, 23-Feb-2026 00:35:17 GMT; Max-Age=1209600; Secure; HttpOnly; Path=/", "todoistd=\"/CUdA09psYiwY7pwgn9sRGC/RQQ=?\"; Domain=.todoist.com; Expires=Tue, 09-Feb-2027 00:35:17 GMT; Max-Age=31536000; Secure; HttpOnly; Path=/; SameSite=None"}, "Strict-Transport-Security":[]string{"max-age=31536000; includeSubDomains; preload"}, "Vary":[]string{"Accept-Encoding"}, "Via":[]string{"1.1 180a4e1c2aa6a4d95dc2a1b2b749e54a.cloudfront.net (CloudFront)"}, "X-Amz-Cf-Id":[]string{"1Q5mg2Fzp7y_4Cbhyxro6cfTSjfqvIRH2Bosn_nN6_BcEIirdbQqlQ=="}, "X-Amz-Cf-Pop":[]string{"ORD56-P14"}, "X-Cache":[]string{"Miss from cloudfront"}}, Body:(*http.http2gzipReader)(0xc000580120), ContentLength:-1, TransferEncoding:[]string(nil), Close:false, Uncompressed:true, Trailer:http.Header(nil), Request:(*http.Request)(0xc000512280), TLS:(*tls.ConnectionState)(0xc00045b5c0)}
trevo@tulkas:~$ todoist sync
trevo@tulkas:~$ todoist list -f "overdue"
6fx8fw3jv7jw7cXc p4 26/02/07(Sat) 00:00 #Inbox  Test task

Decoding the query params on these two requests:


    {
      "args": {
        "due": {
          "date": "",
          "timezone": "",
          "is_recurring": false,
          "string": "",
          "lang": ""
        },
        "id": "6fx8fw3jv7jw7cXc",
        "labels": [
          ""
        ],
        "priority": 1
      },
      "temp_id": "ce00432f-a493-4429-a45c-70f3b027d0ae",
      "type": "item_update",
      "uuid": "8ffea1cd-a0c7-44f7-806f-30782af7d9c8"
    }
    {
      "args": {
        "id": "6fx8fw3jv7jw7cXc",
        "project_id": "0"
      },
      "temp_id": "4734a008-a3fe-48e7-915f-755625e156db",
      "type": "item_move",
      "uuid": "591ebebd-850a-4045-960d-ef495e3db5cd"
    }

So, unless there's more body data hidden somewhere that's not reported in the debug output, it sure seems like the tool is just sending blank data with the requests.

What's weird is I thought I had this working just a few days ago and nothing has changed since then.

In case it somehow matters, this is on linux ubuntu running in WSL2, with todoist installed via brew.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions