{"record":{"id":"5775059a067bb907","repo":"can1357/oh-my-pi","slug":"owncloud-share-response-did-not-include-an-ocs-env","errorCode":null,"errorMessage":"owncloud share response did not include an OCS envelope","messagePattern":"owncloud share response did not include an OCS envelope","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts","lineNumber":51,"sourceCode":"\tdownloadBase?: string;\n}\n\ninterface PlikFile {\n\tid: string;\n\tname?: string;\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction identifier(value: unknown): string | undefined {\n\treturn typeof value === \"string\" || typeof value === \"number\" ? String(value) : undefined;\n}\n\nfunction ownCloudShare(value: unknown): OwnCloudShare {\n\tif (typeof value !== \"object\" || value === null || !(\"ocs\" in value)) {\n\t\tthrow new Error(\"owncloud share response did not include an OCS envelope\");\n\t}\n\tconst ocs = value.ocs;\n\tif (typeof ocs !== \"object\" || ocs === null || !(\"meta\" in ocs) || !(\"data\" in ocs)) {\n\t\tthrow new Error(\"owncloud share response did not include OCS metadata and data\");\n\t}\n\tconst meta = ocs.meta;\n\tconst data = ocs.data;\n\tif (typeof meta !== \"object\" || meta === null || !(\"statuscode\" in meta)) {\n\t\tthrow new Error(\"owncloud share response did not include an OCS status\");\n\t}\n\tif (typeof data !== \"object\" || data === null || !(\"url\" in data)) {\n\t\tthrow new Error(\"owncloud share response did not include a URL\");\n\t}\n\tconst url = nonEmptyString(data.url);\n\tif (!url) throw new Error(\"owncloud share response did not include a URL\");\n\tconst id = \"id\" in data ? identifier(data.id) : undefined;\n\treturn { statusCode: meta.statuscode, url, ...(id ? { id } : {}) };\n}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts#L33-L69","documentation":"ownCloudShare validates that the share API response contains the OCS envelope (an `ocs` key wrapping `meta` and `data`) and throws when it does not. ownCloud's OCS API normally returns { ocs: { meta, data } }; a response lacking this structure means the endpoint answered but not with an OCS-encoded share payload.","triggerScenarios":"POSTing to the ownCloud share endpoint (share.php/ocs/v1.php or v2) returns JSON/XML without an `ocs` wrapper — e.g. the server returned a plain WebDAV/HTML error, the URL targets the non-OCS share endpoint, or OCS envelope wrapping is disabled (`OCS_API` returned bare data in some v2 configurations).","commonSituations":"Wrong share URL (missing /ocs/v2.php path); ownCloud server returning an HTML login/redirect page because auth failed; server configured with 'show server outline'/bare-JSON mode so the ocs wrapper is absent; hitting Nextcloud vs ownCloud path differences.","solutions":["Confirm the share endpoint URL is the OCS one (…/ocs/v2.php/apps/files_sharing/api/v1/shares) and that Accept/format=json is set.","Check authentication: a failed login often returns an HTML page without the ocs envelope; verify app password/token.","Log the raw response body to see whether it is HTML (auth/redirect issue) or bare JSON (envelope-mode issue).","Try adding OCS-APIRequest: true header, required by many ownCloud versions to return the OCS envelope."],"exampleFix":"// before\nawait fetch(`${base}/remote.php/dav/files/`, { method: \"POST\", headers: { Authorization: auth } });\n// after\nawait fetch(`${base}/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json`, {\n  method: \"POST\",\n  headers: { Authorization: auth, \"OCS-APIRequest\": \"true\" },\n  body: form,\n});","handlingStrategy":"type-guard","validationCode":"const res = await fetch(shareUrl, { headers: { \"OCS-APIRequest\": \"true\", Accept: \"application/json\", Authorization: auth } });\nconst body = await res.json();\nif (typeof body !== \"object\" || body === null || !(\"ocs\" in body)) {\n  throw new Error(`non-OCS response from share endpoint: ${JSON.stringify(body).slice(0, 200)}`);\n}","typeGuard":"function isOcsEnvelope(v: unknown): v is { ocs: { meta: unknown; data: unknown } } {\n  if (typeof v !== \"object\" || v === null || !(\"ocs\" in v)) return false;\n  const ocs = (v as { ocs: unknown }).ocs;\n  return typeof ocs === \"object\" && ocs !== null && \"meta\" in ocs && \"data\" in ocs;\n}","tryCatchPattern":"try {\n  const share = await share(destination, request);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"OCS envelope\")) {\n    logger.error(\"ownCloud share endpoint returned non-OCS body; check URL/auth/OCS-APIRequest header\", { err });\n  } else throw err;\n}","preventionTips":["use the full OCS path (/ocs/v2.php/apps/files_sharing/api/v1/shares) not the WebDAV path","always send OCS-APIRequest: true and Accept: application/json","verify auth with a cheap OCS call (getuser) before sharing","log raw bodies to distinguish HTML auth redirects from bare-JSON envelope modes"],"tags":["owncloud","ocs","api-response","self-hosted"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}