Molunerfinn/PicGo · error

PICGO_CLOUD_CONFIG_SYNC_LOCAL_CONFIG_INVALID

Error message

PICGO_CLOUD_CONFIG_SYNC_LOCAL_CONFIG_INVALID

What it means

readLocalConfigWithComments parses ~/.picgo/config.json with a comment-preserving parser and requires the result to be a plain object before it is used for PicGo Cloud config sync. If the file parses to a non-object (array, string, number, null, or garbage), it throws PICGO_CLOUD_CONFIG_SYNC_LOCAL_CONFIG_INVALID. This protects the sync flow from operating on a structurally broken local config.

Source

Thrown at src/main/events/rpc/routes/cloud.ts:140

}

const buildConfigSyncState = async (): Promise<IPicGoCloudConfigSyncState> => {
  return {
    sessionStatus: configSyncSessionStatus,
    encryptionMethod: getLocalEncryptionMethod(),
    lastSyncedAt: await getSnapshotUpdatedAt(),
    conflicts: configSyncSessionStatus === IPicGoCloudConfigSyncSessionStatus.CONFLICT ? configSyncConflictItems : undefined
  }
}

const readLocalConfigWithComments = async (): Promise<IConfig> => {
  if (!(await fs.pathExists(picgo.configPath))) {
    return picgo.getConfig<IConfig>()
  }
  const content = await fs.readFile(picgo.configPath, 'utf8')
  const parsed: unknown = parse(content)
  if (!isPlainObject(parsed)) {
    throw new Error(T('PICGO_CLOUD_CONFIG_SYNC_LOCAL_CONFIG_INVALID'))
  }
  return parsed as IConfig
}

const extractConflictItems = (diffTree: IDiffNode): IPicGoCloudConfigSyncConflictItem[] => {
  const items: IPicGoCloudConfigSyncConflictItem[] = []

  const walk = (node: IDiffNode, pathSegments: string[]) => {
    const nextSegments = node.key === 'root' ? pathSegments : [...pathSegments, node.key]

    if (node.status === ConflictType.CONFLICT) {
      // If the conflict is an object-level aggregation, surface leaf conflicts instead.
      if (node.children && node.children.length > 0) {
        node.children.forEach(child => walk(child, nextSegments))
        return
      }

      items.push({

View on GitHub (pinned to 07ec7068a5)

Solutions

  1. Open picgo.configPath (default ~/.picgo/config.json) and make it a valid JSON object, e.g. {}
  2. Back up and delete/recreate the config file, letting PicGo regenerate defaults
  3. Validate the file with JSON.parse (after stripping comments) before triggering cloud sync
  4. Restore the config from a backup or re-configure uploaders via the UI

Example fix

// before
~/.picgo/config.json => "just a string"
// after
~/.picgo/config.json => { "picBed": { "current": "github" } }
Defensive patterns

Strategy: type-guard

Validate before calling

const raw = JSON.parse(stripJsonComments(fs.readFileSync(configPath, 'utf8')))
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
  throw new Error('config.json must be a JSON object')
}

Type guard

function isPlainObject(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}

Try / catch

try {
  await startCloudSync()
} catch (e) {
  if (e.message.includes('LOCAL_CONFIG_INVALID')) {
    await backupAndResetConfigFile(configPath)
  } else throw e
}

Prevention

When it happens

Trigger: Starting a cloud config sync when picgo.configPath exists but its content is not a JSON object — e.g. the file contains 'null', '[1,2]', a bare string, or content that a comment-tolerant parser resolves to a non-object.

Common situations: Config file truncated/corrupted by a crash or disk-full during write; user hand-edited config.json into invalid or non-object JSON; another tool overwrote the PicGo config with a different format.

Related errors


AI-assisted analysis of Molunerfinn/PicGo@07ec7068a5 (2026-08-30). Data as JSON: /api/errors/22944fe9a0de2a6f. Report an issue: GitHub.