Append upload lets you add content to an existing appendable object without replacing it — useful for streaming logs, live data feeds, or any scenario where you write data incrementally. This topic explains how to use the appendObject method in OSS SDK for Harmony 2.0.
Prerequisites
Before you begin, make sure you have:
An OSS bucket (see Regions and endpoints for region and endpoint formats)
Credentials from Security Token Service (STS): AccessKey ID, AccessKey secret, and security token
The required permissions (see Permissions)
How it works
When you call appendObject:
If the object does not exist, OSS creates a new appendable object and writes the data to it.
If the object exists and is appendable, OSS appends the data at the specified
position. The position must equal the current object length; otherwise, OSS returns aPositionNotEqualToLengtherror.If the object exists but is not appendable, OSS returns an
ObjectNotAppendableerror.
For the first append, omit the position parameter. For each subsequent append, read the next position from the x-oss-next-append-position response header and pass it as position.
Permissions
Alibaba Cloud accounts have full permissions by default. RAM users and RAM roles have no permissions by default and must be granted access through a RAM Policy or bucket policy.
| API | Action | Description |
|---|---|---|
AppendObject | oss:PutObject | Required to append data to an object |
AppendObject | oss:PutObjectTagging | Required when you set object tags via the x-oss-tagging header during append upload |
Append a string
The following example appends a string to an object. On the first call, if the object does not exist, OSS creates it as an appendable object.
import Client, { RequestError } from '@aliyun/oss';
const client = new Client({
accessKeyId: '<your-access-key-id>', // AccessKey ID from STS
accessKeySecret: '<your-access-key-secret>', // AccessKey secret from STS
securityToken: '<your-security-token>', // Security token from STS
region: 'oss-cn-hangzhou', // Region where the bucket is located
});
const bucket = '<your-bucket-name>';
const key = '<your-object-name>';
const appendString = async () => {
try {
const res = await client.appendObject({
bucket,
key,
data: 'hello world',
// Omit `position` on the first append; OSS creates the object and returns the next position.
});
console.log(JSON.stringify(res));
} catch (err) {
if (err instanceof RequestError) {
console.log('code:', err.code);
console.log('message:', err.message);
console.log('requestId:', err.requestId);
console.log('status:', err.status);
console.log('ec:', err.ec);
} else {
console.log('unknown error:', err);
}
}
};
appendString();Replace the placeholders with your actual values:
| Placeholder | Description | Example |
|---|---|---|
<your-access-key-id> | AccessKey ID from STS | LTAI5tXxx |
<your-access-key-secret> | AccessKey secret from STS | xXxXxX |
<your-security-token> | Security token from STS | — |
<your-bucket-name> | Name of the bucket | my-bucket |
<your-object-name> | Name of the object to append to | logs/app.log |
Append multiple data blocks
For sequential appends, read x-oss-next-append-position from each response and pass it as position in the next call.
import Client, { RequestError, EHeaderKey } from '@aliyun/oss';
const client = new Client({
accessKeyId: '<your-access-key-id>',
accessKeySecret: '<your-access-key-secret>',
securityToken: '<your-security-token>',
region: 'oss-cn-hangzhou',
});
const bucket = '<your-bucket-name>';
const key = '<your-object-name>';
const appendMultiple = async () => {
try {
// First append — omit `position` to create the appendable object
const res = await client.appendObject({
bucket,
key,
data: 'first chunk data',
});
console.log(JSON.stringify(res));
// Read the next append position from the response header
const nextAppendPosition = Number(
res.origRes.headers[EHeaderKey.X_OSS_NEXT_APPEND_POSITION]
);
// Second append — pass `position` to write at the correct offset
const res1 = await client.appendObject({
bucket,
key,
data: 'second chunk data',
position: nextAppendPosition,
});
console.log(JSON.stringify(res1));
} catch (err) {
if (err instanceof RequestError) {
console.log('code:', err.code);
console.log('message:', err.message);
console.log('requestId:', err.requestId);
console.log('status:', err.status);
console.log('ec:', err.ec);
} else {
console.log('unknown error:', err);
}
}
};
appendMultiple();Error reference
| Error code | Cause |
|---|---|
PositionNotEqualToLength | The position value does not match the current object length. Read x-oss-next-append-position from the previous response and retry. |
ObjectNotAppendable | The object exists but was not created with append upload. Only appendable objects support AppendObject. |
What's next
Multipart upload — upload large objects in parallel parts
Simple upload — upload an entire object in a single request