{"record":{"id":"215072d327d50ffe","repo":"jackwener/OpenCLI","slug":"returned-no-success-evidence-215072","errorCode":null,"errorMessage":" returned no success evidence","messagePattern":" returned no success evidence","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/instagram/save.js","lineNumber":47,"sourceCode":"    } catch {\n      throw new Error(label + ' returned invalid JSON');\n    }\n  }\n  function getPostFromFeed(feed, label) {\n    if (!feed || typeof feed !== 'object' || !Array.isArray(feed.items)) {\n      throw new Error(label + ' returned malformed items payload');\n    }\n    if (idx >= feed.items.length) throw new Error('Post index ' + (idx + 1) + ' not found');\n    const post = feed.items[idx];\n    const pkRaw = post?.pk ?? post?.id;\n    const pk = typeof pkRaw === 'number' ? String(pkRaw) : (typeof pkRaw === 'string' ? pkRaw.trim() : '');\n    if (!/^\\\\d+$/.test(pk)) throw new Error(label + ' returned malformed post row');\n    const caption = typeof post?.caption?.text === 'string' ? post.caption.text.substring(0, 60) : '';\n    return { pk, caption };\n  }\n  function assertOkStatus(payload, label) {\n    if (!payload || typeof payload !== 'object' || payload.status !== 'ok') {\n      throw new Error(label + ' returned no success evidence');\n    }\n  }\n\n  // web_profile_info answers HTTP 400 for business accounts; feed-by-username needs no user id. See #2234.\n  const r1 = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=' + (idx + 1), opts);\n  if (!r1.ok) throw new Error(r1.status === 404 ? 'User not found: ' + username : 'HTTP ' + r1.status + ' - make sure you are logged in to Instagram');\n  const { pk, caption } = getPostFromFeed(await readInstagramJson(r1, 'Instagram feed-by-username'), 'Instagram feed-by-username');\n\n  const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';\n  const r2 = await fetch('https://www.instagram.com/api/v1/web/save/' + pk + '/save/', {\n    method: 'POST', credentials: 'include',\n    headers: { ...headers, 'X-CSRFToken': csrf, 'Content-Type': 'application/x-www-form-urlencoded' },\n  });\n  if (!r2.ok) throw new Error('Failed to save: HTTP ' + r2.status);\n  assertOkStatus(await readInstagramJson(r2, 'Instagram save'), 'Instagram save');\n  return [{ status: 'Saved', user: username, post: caption || '(post #' + (idx+1) + ')' }];\n})()\n` },","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/save.js#L29-L65","documentation":"Thrown by `assertOkStatus` after the save POST succeeds at the HTTP level: the parsed JSON body must be an object with `status === 'ok'`. If the save endpoint (/api/v1/web/save/<pk>/save/) returns JSON without `status: 'ok'` (e.g. `{\"status\": \"fail\"}` or an error object with HTTP 200/2xx), the CLI treats the save as unverified and throws.","triggerScenarios":"POST /api/v1/web/save/<pk>/save/ returns an HTTP 2xx response whose JSON body lacks `status: 'ok'` — e.g. Instagram returns a soft-failure object (rate limit, action blocked, session flagged) with status 200, or the CSRF token sent was stale so the server returns a non-ok status envelope.","commonSituations":"Instagram has flagged the account for automation and silently rejects the save; the csrftoken cookie read from document.cookie is empty or expired; the account hit a save/action limit; Instagram A/B test changes the response envelope.","solutions":["Refresh the Instagram session and csrftoken (re-login in the CLI browser profile) and retry — a stale CSRF token commonly causes soft failures.","Retry after a delay if the account is rate-limited or action-blocked; avoid rapid repeated saves.","Check the response body (DevTools/verbose logging) to see the actual status/message Instagram returned.","Verify on instagram.com whether the post was actually saved — sometimes the save succeeds despite a non-standard envelope."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isSaveSuccess(payload) {\n  return payload !== null && typeof payload === 'object' && payload.status === 'ok';\n}","tryCatchPattern":"try {\n  await run(['instagram', 'save', username, '--index', String(i)]);\n} catch (e) {\n  if (String(e.message).includes('returned no success evidence')) {\n    // soft failure with 2xx: refresh session/CSRF and back off before retrying\n    await refreshInstagramLogin();\n    return retryWithBackoff(() => run(['instagram', 'save', username, '--index', String(i)]), { attempts: 2, baseDelayMs: 30000 });\n  }\n  throw e;\n}","preventionTips":["Re-login periodically so the csrftoken cookie is current.","Throttle saves — rapid writes get soft-blocked with 2xx fail envelopes.","Spot-check instagram.com that saves actually landed after bulk operations."],"tags":["csrf","instagram","authentication","soft-failure"],"backgroundTag":"api-soft-failure","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}