Aws-sam-cli: start-api (Function returned an invalid response: invalid character '-')

Created on 2 Oct 2017  路  13Comments  路  Source: aws/aws-sam-cli

_Note: My function is working correctly on the real AWS Lambda service!_

Could anyone suggestion why 'sam local start-api' is failing to parse responses but call the function directly works fine?

Parse failure results in 500 response:
bash 2017/10/02 09:43:22 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): invalid character '-' after top-level value

Function invoke appears to be working:
````bash
$ sam local invoke "Hapihello" -e event.json
2017/10/02 09:46:21 Successfully parsed template.yml
2017/10/02 09:46:21 Connected to Docker 1.30
2017/10/02 09:46:21 Fetching lambci/lambda:nodejs6.10 image for nodejs6.10 runtime...
nodejs6.10: Pulling from lambci/lambda
Digest: sha256:7eb4ced6a15ae3c30effc4ec0cd3aabb2bd57c9a8330b37920c3d5d722d81083
Status: Image is up to date for lambci/lambda:nodejs6.10
2017/10/02 09:46:22 Invoking index.handler (nodejs6.10)
START RequestId: 70e1b93c-0e32-19ce-53b1-537a0d2d6381 Version: $LATEST
2017-10-02T08:46:24.192Z 70e1b93c-0e32-19ce-53b1-537a0d2d6381 Registering plugins!!!!
2017-10-02T08:46:24.540Z 70e1b93c-0e32-19ce-53b1-537a0d2d6381 Setting Host to 8ed23ddcaefb:8000
2017-10-02 08:46:24,545, [response] http://8ed23ddcaefb:8000: get /Property-API/0.0.1/api-docs {} 200 (18ms)
END RequestId: 70e1b93c-0e32-19ce-53b1-537a0d2d6381
REPORT RequestId: 70e1b93c-0e32-19ce-53b1-537a0d2d6381 Duration: 1140.68 ms Billed Duration: 0 ms Memory Size: 0 MB Max Memory Used: 60 MB

{"statusCode":200,"body":"{\"swagger\":\"2.0\",\"info\":{\"version\":\"0.0.1\",\"title\":\"Property API\",\"description\":\"An API to query
````

I'm running

  • Windows 10 Pro
  • Docker version 17.06.2-ce, build cec0b72
  • sam version 0.2.2

For me the API server starts fine and serves events but they fail with a strange parse error:
````bash
alexb@DESKTOP-5HFQQQL MINGW64 ~/PhpstormProjects/swaggerizeTest (master)
$ sam local start-api
2017/10/02 09:43:13 Connected to Docker 1.30
2017/10/02 09:43:13 Fetching lambci/lambda:nodejs6.10 image for nodejs6.10 runtime...
nodejs6.10: Pulling from lambci/lambda
Digest: sha256:7eb4ced6a15ae3c30effc4ec0cd3aabb2bd57c9a8330b37920c3d5d722d81083
Status: Image is up to date for lambci/lambda:nodejs6.10

Mounting index.handler (nodejs6.10) at http://127.0.0.1:3000/Property-API/0.0.1/api-docs [GET]
Mounting static files from public at /

You can now browse to the above endpoints to invoke your functions.
You do not need to restart/reload SAM CLI while working on your functions,
changes will be reflected instantly/automatically. You only need to restart
SAM CLI if you update your AWS SAM template.

2017/10/02 09:43:20 Invoking index.handler (nodejs6.10)
START RequestId: 1241967b-5342-17a2-79d5-7d76b518bc81 Version: $LATEST
2017-10-02T08:43:22.361Z 1241967b-5342-17a2-79d5-7d76b518bc81 Registering plugins!!!!
2017-10-02T08:43:22.712Z 1241967b-5342-17a2-79d5-7d76b518bc81 Setting Host to 4b2cfc67527a:8000
END RequestId: 1241967b-5342-17a2-79d5-7d76b518bc81
REPORT RequestId: 1241967b-5342-17a2-79d5-7d76b518bc81 Duration: 1241.16 ms Billed Duration: 0 ms Memory Size: 0 MB Max Memory Used: 59 MB
2017/10/02 09:43:22 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): invalid character '-' after top-level value
````

The contents of my template.yml:
````bash
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
Hapihello:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs6.10
Events:
ApiDocs:
Type: Api
Properties:
Path: /Property-API/0.0.1/api-docs
Method: get
````

The contents of my index.js:
````javascript
'use strict';

const server = require('./server');

/**

  • This module maps the Lambda proxy requests to the Hapijs router
    */
    exports.handler = (event, context, callback) => {
server.makeReady((err) => {

    if (err) throw err;

    // map lambda event to hapi request
    const options = {
        method: event.httpMethod,
        url: event.path,
        payload: event.body,
        headers: event.headers,
        validate: false
    };

    server.inject(options, function (res) {
        const response = {
            statusCode: res.statusCode,
            body: JSON.stringify(res.result),
        };
        callback(null, response);
    });

});

};
````

The contents of my server.js:
````javascript
'use strict';

let Hapi = require('hapi');
let Swaggerize = require('swaggerize-hapi');
let Path = require('path');

const config = require('./config'); // application configuration
const monitor = require('./monitor'); // Monitoring, logging

let Server = new Hapi.Server();

Server.connection({
port: 8000
});

const plugins = [config, monitor];

let loaded = false;
Server.makeReady = function(onServerReady){
if(!loaded){
console.log('Registering plugins!!!!');

    Server.register({
        register: Swaggerize,
        options: {
            api: Path.resolve('./config/swagger.json'),
            handlers: Path.resolve('./handlers')
        }
    }, function () {
        Server.plugins.swagger.setHost(Server.info.host + ':' + Server.info.port);
        console.log('Setting Host to %s:%d', Server.info.host, Server.info.port);
    });

    Server.register(plugins, onServerReady);

    loaded = true;
}
else{
    onServerReady(null);
}

};

module.exports = Server;
````

Many thanks for any suggestions / advice

Alex

Most helpful comment

I'm also encountering something like this issue.

2018/01/07 19:26:04 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): json: cannot unmarshal string into Go value of type struct { StatusCode json.Number "json:\"statusCode\""; Headers map[string]string "json:\"headers\""; Body json.Number "json:\"body\"" }

It has to do w/ the callback object. If I try to pass in something that is not a JSON object, such as a plain string message.

callback(null, "success");

then i get the error:

2018/01/07 19:35:02 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): json: cannot unmarshal string into Go value of type struct { StatusCode json.Number "json:\"statusCode\""; Headers map[string]string "json:\"headers\""; Body json.Number "json:\"body\"" }

If I create the callback object as an json object similar to the error message, then it does return 200 OK and quiets down.

however, looking at lambda docs - it seems to indicate that returning a value of any type (string, structure or nothing) should be a valid behavior.

All 13 comments

not sure if this can be the prob but maybe it has to do with the Path: /Property-API/0.0.1/api-docs that it can not read the "-" did you try just making it an easy path like / or /production. just a sugestion

Just tried it with another URL which doesn't have a hyphen in the URL but same error.

Thanks for the suggestion though.

hmmm,
I had the same error but with a 'p' and found out it had something to do with my Json parsing but not sure if that is the same in your case.
{in: " 42 \x01", err: &SyntaxError{"invalid character '\x01' after top-level value", 5}}, something to do with unmarsheling in the .go file as i can see quicklly from here: https://golang.org/src/encoding/json/decode_test.go line 430

The error signifies that SAM Local couldn't parse your response properly. Since invoke works, I suspect there is a problem with generating the event from the HTTP request you're sending. This problem may be solved by #143, but to be sure I need to view event.json

Thanks,

I used the generate-event command to create the event.json file the tweaked proxy and path's manually. I didn't really know what I was doing but this seemed sensible haha

javascript { "body": "{ \"test\": \"body\"}", "resource": "/{proxy+}", "requestContext": { "resourceId": "123456", "apiId": "1234567890", "resourcePath": "/{proxy+}", "httpMethod": "POST", "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", "accountId": "123456789012", "identity": { "apiKey": null, "userArn": null, "cognitoAuthenticationType": null, "caller": null, "userAgent": "Custom User Agent String", "user": null, "cognitoIdentityPoolId": null, "cognitoIdentityId": null, "cognitoAuthenticationProvider": null, "sourceIp": "127.0.0.1", "accountId": null }, "stage": "prod" }, "queryStringParameters": { "foo": "bar" }, "headers": { "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", "Accept-Language": "en-US,en;q=0.8", "CloudFront-Is-Desktop-Viewer": "true", "CloudFront-Is-SmartTV-Viewer": "false", "CloudFront-Is-Mobile-Viewer": "false", "X-Forwarded-For": "127.0.0.1, 127.0.0.2", "CloudFront-Viewer-Country": "US", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Upgrade-Insecure-Requests": "1", "X-Forwarded-Port": "443", "Host": "1234567890.execute-api.us-east-1.amazonaws.com", "X-Forwarded-Proto": "https", "X-Amz-Cf-Id": "aaaaaaaaaae3VYQb9jd-nvCd-de396Uhbp027Y2JvkCPNLmGJHqlaA==", "CloudFront-Is-Tablet-Viewer": "false", "Cache-Control": "max-age=0", "User-Agent": "Custom User Agent String", "CloudFront-Forwarded-Proto": "https", "Accept-Encoding": "gzip, deflate, sdch" }, "pathParameters": { "proxy": "/Property-API/0.0.1/api-docs" }, "httpMethod": "GET", "stageVariables": { "baz": "qux" }, "path": "/Property-API/0.0.1/api-docs" }

I'm also encountering something like this issue.

2018/01/07 19:26:04 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): json: cannot unmarshal string into Go value of type struct { StatusCode json.Number "json:\"statusCode\""; Headers map[string]string "json:\"headers\""; Body json.Number "json:\"body\"" }

It has to do w/ the callback object. If I try to pass in something that is not a JSON object, such as a plain string message.

callback(null, "success");

then i get the error:

2018/01/07 19:35:02 Function returned an invalid response (must include one of: body, headers or statusCode in the response object): json: cannot unmarshal string into Go value of type struct { StatusCode json.Number "json:\"statusCode\""; Headers map[string]string "json:\"headers\""; Body json.Number "json:\"body\"" }

If I create the callback object as an json object similar to the error message, then it does return 200 OK and quiets down.

however, looking at lambda docs - it seems to indicate that returning a value of any type (string, structure or nothing) should be a valid behavior.

See Set up Lambda Proxy Integrations in API Gateway

The expectation is that your handler will return a special JSON document that can be used by API Gateway to construct a proper HTTP response:

{
  "isBase64Encoded": true|false,
  "statusCode": httpStatusCode,
  "headers": { "headerName": "headerValue", ... },
  "body": "..."
}

@abatkin thanks for pointing that out. i did not realize sam integration extended to including api gateway but now the response format warning makes sense.

If you turn off all logging output, does the issue go away? I know there is an issue with the Java runtime where the sam runtime takes some of the log messages in as part of the response. This sounds like a similar issue

Can you try the latest release - https://github.com/awslabs/aws-sam-cli/releases/tag/v0.3.0? I believe this is fixed. Feel free to re-open Issue if not.

@sanathkr This issue still exists on sam 0.14.2. And the root cause, as mentioned by @sbuzonas , is due to log messages. Setting root log level to ERROR solved this problem.

@seanyinx Logging within your Java function? If so, yes this can happen because of how docker-lambda containers handle and return response & logs via the same stream. If the logs gets interspersed with your response, then SAM CLI will fail to parse your response.

@sanathkr yes, thank you for clarification.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

goldenbearkin picture goldenbearkin  路  3Comments

cvuijst picture cvuijst  路  3Comments

red8888 picture red8888  路  3Comments

terlar picture terlar  路  3Comments

jpbarto picture jpbarto  路  4Comments