When POST /rest/posts fails, LinkedIn answers with an HTTP status and a JSON body holding a message, a
serviceErrorCode and the status. The message is usually specific enough to act on, so read it first.
Every LinkedIn fact here comes from LinkedIn's own documentation (API version 202610), checked on October 26, 2026: its error handling, Posts API, sign-in flow, refresh tokens, rate limits, versioning, Images API, Videos API and Documents API pages, and the error table of the legacy UGC Post API. LinkedIn ships a new API version every month, so check the linked page before you build on it.
The short answer
| LinkedIn answers | What it means | What fixes it |
|---|---|---|
| 401, expired or invalid access token | The token is past its 60 days, or wrong | Refresh it if you have a refresh token; otherwise sign the member in again |
| 401, the token has been revoked | The member removed your app on LinkedIn | Sign the member in again |
403 ACCESS_DENIED |
The token lacks the permission, or the member lacks the page role | Add the permission, then get a new token |
| 422, "Content is a duplicate of …" | An identical post was made recently | Wait 10 minutes, or change the text |
422 UNPROCESSABLE_ENTITY |
The request is well-formed, but its values don't fit together | Read the message and fix the field it names |
400 MISSING_FIELD, FIELD_LENGTH_TOO_LONG and similar |
A field is missing, too long or the wrong type | Fix the field the message names |
| 426 | The Linkedin-Version header names a retired version |
Send a current version |
| 429 | A daily limit | Wait for the reset at midnight UTC |
Media status WAITING_UPLOAD or PROCESSING |
The file isn't ready yet | Wait until it's AVAILABLE, then post |
Media status PROCESSING_FAILED |
LinkedIn couldn't process the file | Fix the file and upload it again |
| 500, 503 or 504 | A problem on LinkedIn's side | Check the profile for the post, then retry |
401: expired, invalid or revoked tokens
LinkedIn's error handling page lists the 401s:
| Message | What fixes it |
|---|---|
| Unknown authentication schema | Send Authorization: Bearer <access token> |
Empty OAuth2 access token (EMPTY_ACCESS_TOKEN in the Posts API) |
The header is missing or empty: send the token |
| Invalid access token | Get a correct token through the sign-in flow |
| Expired access token | Refresh the token |
| The token has been revoked | The member revoked your app in their LinkedIn settings, so they sign in again |
How long tokens last:
- Access tokens last 60 days.
expires_ingives the seconds left (5,184,000 for a new token). LinkedIn doesn't issue longer-lived ones. - Refresh tokens are for approved partners. LinkedIn offers programmatic refresh tokens to approved Marketing Developer Platform partners. One lasts a year from the first sign-in, and each refresh gives a new 60-day access token without restarting that year. When it ends, the member signs in again.
- Without a refresh token, as with the self-serve Share on LinkedIn product, you renew by sending the member through sign-in again. LinkedIn skips the consent screen when the member is still signed in to linkedin.com and their current token hasn't expired, so renew before day 60.
- New scopes end old tokens. Requesting a different set of permissions than the member granted before invalidates every earlier access token.
- Some token failures are 500s. LinkedIn says a failure while it verifies the token returns 500, not 401.
403: missing permissions
ACCESS_DENIED means the token doesn't carry the permission the call needs, or the member doesn't have the role it
needs. LinkedIn's Posts API names the permissions: w_member_social to post as the member, w_organization_social to
post as a company page, which also takes the member's role on that page. Check, in order:
- The app has the product.
w_member_socialcomes with the self-serve Share on LinkedIn product;w_organization_socialwith the vetted Community Management API (what each permission covers). - The member granted it. A permission has to be in the sign-in request. If you added it after the member signed in, sign them in again for a token that has it. LinkedIn's checklist asks whether your app changed the scope when it requested the token.
- The author is the member. Post as
urn:li:person:{id}for the member whose token you use. Their photos, videos and documents must belong to them too: LinkedIn checks that the caller matches the media's owner. - The call isn't a read. LinkedIn's Images API says
w_member_socialis write-only: a token with only that permission can't make versionedGET /rest/imagescalls and gets 403 "Accessing this image resource is forbidden". The Documents API's equivalent isDOCUMENT_FORBIDDEN.
LinkedIn also says some restricted APIs answer 404 rather than 403.
400 and 422: content errors
The Posts API's error table:
| Status | Code | What it means |
|---|---|---|
| 400 | MISSING_FIELD |
A required field, such as author, visibility, distribution or lifecycleState, is missing |
| 400 | INVALID_VALUE_FOR_FIELD |
A value isn't allowed, such as an unknown visibility, feedDistribution or lifecycleState |
| 400 | FIELD_LENGTH_TOO_LONG |
commentary or another text field is too long |
| 400 | INVALID_VALUE_BLANK_FIELD |
A required text field is empty |
| 400 | INVALID_URN_TYPE or INVALID_URN_ID |
A URN, often author or content.media.id, is the wrong type or malformed |
| 409 | CONFLICT |
A write conflict: retry |
| 422 | UNPROCESSABLE_ENTITY |
Well-formed, but the values don't fit together |
Duplicates. LinkedIn documents the duplicate refusal in its legacy UGC Post API's error table: 422 "Content is a duplicate of {share or UGC URN}", meaning an exact duplicate of a recently created post. Wait 10 minutes for the restriction to end, or change the content. The newer Posts API's table lists only the general 422. The same UGC table lists 422 "Error validating the post", whose message gives the reason, such as a missing or too-long field.
Media upload states
Photos, videos and documents are uploaded before the post, and each has a status. Post only once it's AVAILABLE:
| Status | What it means | What to do |
|---|---|---|
WAITING_UPLOAD |
LinkedIn is waiting for the file, or for its upload to finish | Finish the upload; a video also needs its finalize call |
PROCESSING |
LinkedIn is still preparing it | Check again later, and don't post yet |
AVAILABLE |
It's ready | Post it |
PROCESSING_FAILED |
A file too large, an unsupported format or an error on LinkedIn's side | Fix the file and upload it again; a video's processingFailureReason says why |
- Upload URLs expire. Each upload URL comes with an expiry. Video upload URLs typically last 30 days from the start of
the upload; uploading to an expired one answers 401, and the Videos API also lists 400
EXPIRED_UPLOAD_URL. - Video parts. Upload each part to the URLs LinkedIn returns, keep each part's
ETagresponse header, then finalize with theuploadTokenand those IDs in order. - Posting too soon. A post whose video is still waiting, or failed, is refused with 400
MEDIA_ASSET_WAITING_UPLOADorMEDIA_ASSET_PROCESSING_FAILED.
LinkedIn's limits for each kind:
| Media | LinkedIn's limit |
|---|---|
| Photos | JPG, GIF or PNG, under 36,152,320 pixels; GIFs up to 250 frames |
| Video | MP4, 3 seconds to 30 minutes, 75 KB to 500 MB |
| Documents | PDF, PPT, PPTX, DOC or DOCX, up to 100 MB and 300 pages |
429: rate limits
LinkedIn counts calls per 24 hours, resetting at midnight UTC, with one limit for your app and one for each member using it. It doesn't publish the standard limits: your app's Analytics tab in the Developer Portal shows them for each endpoint you've called. The Share on LinkedIn product lists 150 requests per member and 100,000 per app each UTC day. The 429's message reads "Resource level throttle limit for calls to this resource is reached."
- Wait for the reset, and cut repeated calls.
- A share limit. The legacy UGC Post table also lists 429 "UGC action was blocked because a share limit has been reached": the author hit a daily limit on posts.
- Protective 429s. LinkedIn sometimes returns a 429 to protect its systems; it clears by itself.
- Alerts. Developer admins get an email when the app passes 75% of a limit, about one to two hours late.
426: an old API version
The versioned /rest API needs a Linkedin-Version: YYYYMM header. LinkedIn releases a version every month and
supports each for at least a year. A retired version gets 426, and a request without the header gets an error too.
Version 202511 is retired on November 16, 2026. Move the header to a current version, then check what changed since.
500, 503 and 504
These are LinkedIn's side: retry with backoff. If 500s keep coming, LinkedIn asks for the request, the response headers
(x-li-uuid, x-li-fabric and x-li-request-id) and your app's client ID in a support request. Before you retry
creating a post, look at the profile: an error answer doesn't prove the post wasn't made.
Posting through Flaghand
Flaghand's check stops several of these before anyone approves a post: text over 3,000 characters counted the way LinkedIn's post box counts, more than 20 photos, alt text over 4,086 characters, a video that isn't a single MP4 of 75 KB to 500 MB and 3 seconds to 30 minutes, a PDF over 300 pages, a company tag without its page's exact name and ID, and a login that runs out before the post time (draft rules). Flaghand's uploads take files up to 50 MB.
After the owner approves it:
- Media waits for
AVAILABLE. Flaghand uploads a video or PDF, checks it each minute while LinkedIn processes it, and posts only once it'sAVAILABLE.PROCESSING_FAILEDends the job without a post. - The job shows LinkedIn's answer, such as
LinkedIn returned HTTP 422:followed by LinkedIn's message. - A 429 is tried again two minutes later, up to three tries in all.
- A 5xx on the post itself isn't resent, since LinkedIn may have made it. The job asks you to look on the profile and approve it again only if the post isn't there.
- A 401 holds the job. The owner reconnects LinkedIn in Settings, then retries the post in the desk. LinkedIn logins last 60 days, and the desk flags one a week before it ends.
- No read-back. Flaghand can't read LinkedIn posts back, so "posted" means LinkedIn accepted it.
Flaghand's own API answers with its own error codes.