johannesjo / super-productivity

Super Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, Gitlab, GitHub and Open Project.
http://super-productivity.com
MIT License
10.76k stars 863 forks source link

TypeError: Cannot convert undefined or null to object #3395

Open KatrinIhler opened 2 weeks ago

KatrinIhler commented 2 weeks ago

Steps to Reproduce

Had a tag reference the id of a missing task. (Not sure how that happened yet, there's something funky when creating new tasks in the planner view I think). Trying the automatic repair led to this error, reloading the app just led to the invalid app data warning again. I exported the data and removed the broken reference manually. Since you can't get to the import data dialog in this state, I first renamed my data folder. Now I have a working state again... for now.

Error Log (Desktop only)

Console Output

Meta Info

META: SP10.0.1 Electron – en-US – Linux x86_64 – Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) superProductivity/10.0.1 Chrome/126.0.6478.185 Electron/31.3.1 Safari/537.36

Stacktrace

_resetEntityIdsFromObjects (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-repair/data-repair.util.ts:230:16)
_fixEntityStates (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-repair/data-repair.util.ts:45:16)
_fixEntityStates (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-repair/data-repair.util.ts:44:20)
isDataRepairPossible (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-repair/data-repair.util.ts:22:12)
constructor (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-repair/data-repair.service.ts:17:11)
this._dataRepairService.isRepairPossibleAndConfirmed (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/src/app/core/data-init/data-init.service.ts:52:50)
d_ (file:///snap/superproductivity/2025/resources/app.asar/dist/browser/main-C2QDJGNR.js:1:1557)

Actions Before Error

1725283772396: [Persistence] Save to DB 
1725283773398: [Task] Update Task 
1725283773401: [Persistence] Save to DB 
1725283774239: [Task] Update Task 
1725283774242: [Persistence] Save to DB 
1725283775169: [Task] Update Task 
1725283775173: [Persistence] Save to DB 
1725283805296: [WorkContextMeta] Move Task in Today 
1725283805303: [Persistence] Save to DB 
1725283807873: [WorkContextMeta] Move Task in Today 
1725283807877: [Persistence] Save to DB 
1725283818643: [Task] Update Task Tags 
1725283818648: [Persistence] Save to DB (3) 
1725283821117: [Task] Update Task Tags 
1725283821121: [Persistence] Save to DB (3) 
1725284118302: [Task] SetSelectedTask 
1725284118305: [Layout] Hide Notes 
1725284119253: [Task] SetSelectedTask 
1725284120726: [Task] Delete Task 
1725284120733: [Persistence] Save to DB (3) 
1725284120734: [Task] UnsetCurrentTask 
1725284120737: [Persistence] Save to DB 
1725284799861: [Global Config] Update Global Config Section 
1725284801728: [Persistence] Save to DB 
1725284804016: [Global Config] Update Global Config Section 
1725284804048: [Persistence] Save to DB 
1725284804049: [Dropbox] Trigger Auth Dialog 
1725284863373: [Task] UnsetCurrentTask 
1725284863380: [SimpleCounter] Turn off all simple counters 
1725284867774: [FocusMode] Set focus session elapsed time
github-actions[bot] commented 2 weeks ago

Thank you very much for opening up this issue! I am currently a bit overwhelmed by the many requests that arrive each week, so please forgive me, if I fail to respond personally. I am still very likely to at least skim read your request and I'll probably try to fix all (real) bugs if possible and I will likely review every single PR being made (please, give me a heads up if you intent to do so) and I will try to work on popular requests (please upvote via thumbs up on the original issue) whenever possible, but trying to respond to every single issue over the last years has been kind of draining and I need to adjust my approach for this project to remain fun for me and to make any progress with actually coding new stuff. Thanks for your understanding!

johannesjo commented 1 week ago

Thanks for reporting! Do you by any chance still have the broken data somewhere? At least the automatic data repair should work... :/

KatrinIhler commented 1 week ago

I might still have the broken data somewhere but I'm certain I can share them with you since it might contain client information. :/ I've had problems with the automatic repair for quite a while now, might be some leftover from a much earlier SP version doing funky things that are unexpected? If there's something specific you want to know, feel free to ask.

johannesjo commented 6 days ago

I completely understand.

I would need to know what part of the data is broken and causing the error. This might allow me to deduce what is going on.

It's a bit complicated, but you might be able to use the privacy script on the data. You can copy and paste it to the browser console for example and do something like that.

var jsonStr =  '{here you copy in the data export}';
privacyExport(jsonStr);  // should output your data with everything masked

Here is the script:

const dirtyDeepCopy = val => JSON.parse(JSON.stringify(val))

let i = 0

const KEY_TO_REPLACE = [
  "username",
  "userName",
  "password",
  "token",
  "notes",
  "authCode",
  "accessToken",
  "host",
  "gitlabBaseUrl",
  "syncFilePath",
  "syncFolderPath",
  "title",
  "originalImgPath",
  "path",
  "content",

  "repo",
  "repoFullname",
  "filterUserName",
  "caldavUrl",
  "api_key"
]

const maskString = (key, val, counter) => {
  if (KEY_TO_REPLACE.includes(key) && val.length > 0) {
    return `${key}__${counter}`
  } else {
    return val
  }
}

const recurse = obj => {
  // eslint-disable-next-line guard-for-in
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      const val = obj[key]
      if (Array.isArray(val)) {
        val.forEach(arrVal => {
          if (typeof arrVal === "object" && arrVal !== null) {
            recurse(arrVal)
          }
        })
      } else if (typeof val === "object" && val !== null) {
        recurse(val)
      } else if (typeof val === "string") {
        obj[key] = maskString(key, val, i)
      }
    }
    i++
  }
}

export const privacyExport = d => {
  const cpy = dirtyDeepCopy(d)
  recurse(cpy)

  return JSON.stringify(cpy)
}
KatrinIhler commented 5 days ago

Did some more debugging: I think _resetEntityIdsFromObjects in the data-repair class assumes that data.entities exists, which isn't true for my data for at least the key obstruction, if not more. (That one doesn't contain anything but the model version.)

johannesjo commented 4 days ago

Thank you very digging into this! I made the repair script a bit more lenient in terms of the data it requires. That should fix the issue, I hope.